带你入门java雪花算法原理

带你入门java雪花算法原理

概述

雪花算法(Snowflake)是 Twitter 开源的分布式 id 生成算法,以其独特的 id 生成方式,广泛用于分布式系统中唯一 id 的生成,保证了分布式系统中数据的唯一性。

原理

雪花算法生成的 id 是一个 64 位的 long 型整数,其中:

  • 1 bit:表示不可用,Java long 类型的高位是符号位,正数是 0,负数是 1,在这里生成的都是数字,所以是 0。
  • 41 bit:表示毫秒时间戳,用于确保在分布式情况下生成的 id 是全局唯一的,41 bit 能表示的毫秒数大概是 69 年,从 1970 年到 2038 年不会出现时间戳重复问题。
  • 10 bit:表示工作机器 id,可以部署在 1024 台机器上,用于多机器生成 id 的情况下区分是哪台机器生成的 id。
  • 12 bit:表示同一毫秒时间戳内的序列号,用于保证同一毫秒时间戳生成的 id 不会重复。

实现

Java示例

下面是Java实现示例:

public class SnowflakeIdGenerator {
    // 定义起始时间戳,可根据需求更改此值为你们的系统投产时间
    private final static long START_STAMP = 1577808000000L;
    // 定义各位所占用的位数,共64位
    private final static long SEQUENCE_BIT = 12;
    private final static long MACHINE_BIT = 10;
    private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE_NUM = ~(-1L << SEQUENCE_BIT);
    // 定义各位的位移,顺序很重要,否则会出错,从右到左,即从低位到高位
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long TIMESTAMP_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    // 初始序列号
    private long sequence = 0L;
    private long lastStamp = -1L;
    private long machineId;
    /**
     * 构造函数
     * @param machineId 同一时间内生成多个ID时区分各个机器
     */
    public SnowflakeIdGenerator(long machineId) {
        if (machineId > MAX_MACHINE_NUM) {
            throw new RuntimeException("机器码超出最大值~~~");
        }
        this.machineId = machineId;
    }
    /**
     * 生成下一个ID
     * @return long
     */
    public synchronized long nextId() {
        long currStamp = getNewTimestamp();
        if (currStamp < lastStamp) {
            throw new RuntimeException("时间戳倒置:拒绝生成ID~~~");
        }
        if (currStamp == lastStamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE_NUM;
            if (sequence == 0L) {
                currStamp = getNextTimestamp();
            }
        } else {
            sequence = 0L;
        }
        lastStamp = currStamp;
        return (currStamp - START_STAMP) << TIMESTAMP_LEFT| machineId << MACHINE_LEFT | sequence;
    }
    /**
     * 生成一个新的时间戳
     * @return long
     */
    private long getNewTimestamp() {
        return System.currentTimeMillis();
    }
    /**
     * 获取下一个时间戳,必须比当前时间戳大
     * @return
     */
    private long getNextTimestamp() {
        long timestamp = getNewTimestamp();
        while (timestamp <= lastStamp) {
            timestamp = getNewTimestamp();
        }
        return timestamp;
    }
}

示例说明

示例一

以下代码块展示了怎样使用 SnowflakeIdGenerator 类生成一个分布式系统的 id:

public static void main(String[] args) {
    SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(123L);
    long id = snowflake.nextId();
    System.out.println(id);
}

输出结果:

175691630939576320

示例二

以下代码块展示了怎样使用 SnowflakeIdGenerator 类生成两个分布式系统的 id,并比较它们的时间戳、机器码、序列号是否相同:

public static void main(String[] args) {
    SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(123L);
    long id1 = snowflake.nextId();
    long id2 = snowflake.nextId();
    long timestamp1 = (id1 >> 22) + 1577808000000L;
    long timestamp2 = (id2 >> 22) + 1577808000000L;
    long machine1 = (id1 >> 12) & 1023;
    long machine2 = (id2 >> 12) & 1023;
    long sequence1 = id1 & 4095;
    long sequence2 = id2 & 4095;
    System.out.println("id1: " + id1 + ", timestamp: " + timestamp1 + ", machine: " + machine1 + ", sequence: " + sequence1);
    System.out.println("id2: " + id2 + ", timestamp: " + timestamp2 + ", machine: " + machine2 + ", sequence: " + sequence2);
}

输出结果:

id1: 175691630939576320, timestamp: 1584055749065, machine: 123, sequence: 0
id2: 175691634581391872, timestamp: 1584055749289, machine: 123, sequence: 0

总结

通过上述示例,我们可以看出 Snowflake 算法生成分布式系统的 id 是非常简单、高效、可靠的。理解了 Snowflake 算法的原理和实现,我们可以在实际开发中使用 Snowflake 算法来生成分布式系统的唯一 id,保证数据的唯一性,避免出现数据重复问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:带你入门java雪花算法原理 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • MyBatis中关于SQL的写法总结

    下面详细讲解”MyBatis中关于SQL的写法总结”。 概述 MyBatis是一种优秀的Java持久化框架,它提供了丰富的基于XML和注解的SQL语句的支持。对于开发者而言,学会定制SQL语句将提高性能和灵活性。这篇攻略将会总结MyBatis中SQL的写法,让读者更好地了解和使用MyBatis。 基本语法 首先,我们需要了解MyBatis的SQL标签。 se…

    Java 2023年5月20日
    00
  • Java中创建ZIP文件的方法

    创建ZIP文件是Java中常见的操作之一。Java提供了许多方法来操作ZIP文件。下面是创建ZIP文件的完整攻略。 1. 导入相关的包 为了创建ZIP文件,我们需要导入Java的ZipEntry和ZipOutputStream类。ZipEntry类可以表示ZIP文件中的每个条目的元数据,而ZipOutputStream类允许我们将数据写入ZIP文件。 imp…

    Java 2023年5月20日
    00
  • JSP Servelet 数据源连接池的配置

    JSP Servlet数据源连接池的配置需要完成以下步骤: 第一步:导入数据库驱动包 在项目中的WebContent/WEB-INF/lib目录下,将数据库驱动包导入,例如MySQL数据库的驱动包mysql-connector-java-8.0.16.jar。 第二步:在web.xml文件中配置数据源连接池 在web.xml文件中,新增以下内容: <r…

    Java 2023年6月15日
    00
  • mvn compile报错“程序包com.XXX不存在”

    当使用mvn compile命令对Maven项目进行编译时,可能会出现错误提示“程序包com.XXX不存在”的情况。这种错误的产生通常是由于以下两种情况之一: 需要的依赖没有正确添加 本地仓库中缺失相应的依赖包 为了解决这个问题,可以采取以下步骤: 步骤一:确认依赖是否已正确添加 首先需要确认Maven项目的pom.xml文件中是否正确添加了需要的依赖。可以…

    Java 2023年6月2日
    00
  • Java异常–常见方法–自定义异常–增强try(try-with-resources)详解

    Java异常–常见方法–自定义异常–增强try(try-with-resources)详解 Java异常 在 Java 中,运行期的错误被称之为异常(Exception)。在 Java 中,所有异常都是 java.lang.Throwable 类或其子类的实例。异常分为两种类型:检查型异常和非检查型异常(运行时异常)。 检查型异常:需要在代码中显式处理…

    Java 2023年5月27日
    00
  • 解决MyEclipse中Maven设置jdk版本jdk1.8报错问题

    第一步:查看Maven仓库 首先,在MyEclipse中点击菜单栏中的“Window”选项,再依次点击“Show View” -> “Other”,在窗口中选择“Maven” -> “Maven Repositories”,即可打开Maven仓库视图。 第二步:定位jdk1.8版本的安装路径 在Maven仓库视图中,找到”Global Repos…

    Java 2023年5月20日
    00
  • java 中复合机制的实例详解

    Java中复合机制的实例详解 Java中的复合机制是面向对象编程的核心概念之一。本文将详细讲解Java中的复合机制,介绍其实现原理以及两个示例说明。 什么是Java中的复合机制? Java中的复合机制是指对象之间的组合关系。在Java中,类可以通过实例化其他类的对象来实现对其他类对象的管理。这种关系称为“复合关系”,它是Java面向对象编程中的一种重要的机制…

    Java 2023年6月15日
    00
  • Java 精炼解读时间复杂度与空间复杂度

    Java 精炼解读时间复杂度与空间复杂度攻略 什么是时间复杂度与空间复杂度 时间复杂度和空间复杂度是算法分析的两个重要参数。它们用于衡量算法的运行效率和空间消耗。 时间复杂度:衡量算法运行时间的增长率,通常用大O计数法表示。比如O(1)、O(n)、O(n^2)等等。 空间复杂度:衡量算法所需的内存空间大小的增长率,也是用大O计数法表示。和时间复杂度类似,也可…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部