Java实现雪花算法(snowflake)

Java实现雪花算法(snowflake)

雪花算法是一种可以生成全局唯一ID的算法,它可以用于分布式系统中的ID生成。下面是Java实现雪花算法(snowflake)的完整攻略,包含过程中至少两条示例说明。

算法思路

雪花算法可以生成64位的唯一ID,其生成规则如下:

  • 1位标识符:符号位,在雪花算法中始终为0,表示正数。
  • 41位时间戳:记录生成ID的时间,表示从"起始时间"开始经过的毫秒数。41位可以支持69年的时间戳。
  • 10位机器标识:可以部署在1024台机器上,要求在同一毫秒内产生的ID是不同的。
  • 12位序列号:在同一毫秒内,可以产生4096个不同的序列号。

Java实现

Java实现雪花算法,可以使用如下代码:

public class SnowflakeIdGenerator {
    private static final long twepoch = System.currentTimeMillis();

    private static final long workerIdBits = 10L;
    private static final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private static final long sequenceBits = 12L;

    private static final long workerIdShift = sequenceBits;
    private static final long timestampLeftShift = sequenceBits + workerIdBits;
    private static final long sequenceMask = -1L ^ (-1L << sequenceBits);

    private long workerId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    public SnowflakeIdGenerator(long workerId) {
        if (workerId > maxWorkerId || workerId < 0L) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) |
                (workerId << workerIdShift) |
                sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }
}

在上述代码中:

  • twepoch是一个起始时间,用于计算时间戳。
  • workerIdBits是机器标识的位数,为10位,在示例中使用了一个long类型的变量。
  • maxWorkerId是机器标识的最大值,根据机器标识位数计算出来。
  • sequenceBits是序列号的位数,为12位,在示例中使用了一个long类型的变量。
  • workerIdShift是机器标识的左移位数,根据序列号位数计算出来。
  • timestampLeftShift是时间戳的左移位数,根据序列号和机器标识位数计算出来。
  • sequenceMask是序列号的掩码,根据序列号位数计算出来。

在SnowflakeIdGenerator类中,nextId()方法用于生成ID,tilNextMillis()方法用于等待下一毫秒。同时,都使用了synchronized让这些方法保证线程安全。

示例说明

下面是两个示例说明:

示例一

在这个示例中,我们使用一台机器,使用了两个SnowflakeIdGenerator生成10个ID,代码如下:

public class Example1 {
    public static void main(String[] args) {
        SnowflakeIdGenerator generator1 = new SnowflakeIdGenerator(1L);
        SnowflakeIdGenerator generator2 = new SnowflakeIdGenerator(2L);

        for (int i = 0; i < 5; i++) {
            System.out.println(generator1.nextId());
        }

        for (int i = 0; i < 5; i++) {
            System.out.println(generator2.nextId());
        }
    }
}

输出结果:

680131594107310848
680131594107310849
680131594107310850
680131594107310851
680131594107310852
687596776048314881
687596776048314882
687596776048314883
687596776048314884
687596776048314885

示例二

在这个示例中,我们使用三台机器,分别使用了三个SnowflakeIdGenerator生成10个ID,代码如下:

public class Example2 {
    public static void main(String[] args) {
        SnowflakeIdGenerator generator1 = new SnowflakeIdGenerator(1L);
        SnowflakeIdGenerator generator2 = new SnowflakeIdGenerator(2L);
        SnowflakeIdGenerator generator3 = new SnowflakeIdGenerator(3L);

        for (int i = 0; i < 5; i++) {
            System.out.println(generator1.nextId());
        }

        for (int i = 0; i < 5; i++) {
            System.out.println(generator2.nextId());
        }

        for (int i = 0; i < 5; i++) {
            System.out.println(generator3.nextId());
        }
    }
}

输出结果:

854590986602096640
854590986602096641
854590986602096642
854590986602096643
854590986602096644
854590986602096645
854590986602096646
854590986602096647
854590986602096648
854590986602096649
758515964259520513
758515964259520514
758515964259520515
758515964259520516
758515964259520517
973074594719193345
973074594719193346
973074594719193347
973074594719193348
973074594719193349

可以看到,在示例二中,三台机器都可以生成唯一的ID,并且在同一毫秒内产生的ID是不同的。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java实现雪花算法(snowflake) - Python技术站

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

相关文章

  • JSP过滤器防止Xss漏洞的实现方法(分享)

    实现JSP过滤器来防止XSS漏洞的方法如下: 在web.xml文件中添加过滤器配置 在web.xml文件中添加以下过滤器配置: <filter> <filter-name>XssFilter</filter-name> <filter-class>com.example.XssFilter</filter…

    Java 2023年6月15日
    00
  • 详解Java的构造方法及类的初始化

    详解Java的构造方法及类的初始化 Java中的类可以通过定义构造方法来初始化对象的成员变量。本文将介绍Java的构造方法及类的初始化。 构造方法的定义 构造方法是一种特殊的方法,用于在创建对象时初始化对象的成员变量。它具有以下特点: 方法名称和类名称相同 没有返回值类型 可以有多个形参 可以有多个构造方法 以下是一个示例: public class Per…

    Java 2023年5月26日
    00
  • 作为Java程序员应该掌握的10项技能

    作为Java程序员,掌握以下10项技能是非常重要的: 1. 熟悉Java基础知识 Java是一种面向对象的编程语言,因此对于Java程序员来说,熟悉Java基础知识是非常重要的。这包括变量、数据类型、循环、条件语句、方法、类、对象等。 示例: public class Main { public static void main(String[] args)…

    Java 2023年5月20日
    00
  • Spring Security 密码验证动态加盐的验证处理方法

    针对“Spring Security 密码验证动态加盐的验证处理方法”的完整攻略,我将分为以下几个部分进行讲解: 加盐的原理及作用 Spring Security 密码验证流程 实现动态加盐的验证处理方法 示例代码和测试 1. 加盐的原理及作用 在密码存储中,加盐是一种常用的安全策略,其原理是在密码明文前后添加一段随机的字符串(即盐),然后对整个字符串进行哈…

    Java 2023年5月20日
    00
  • Java利用多线程模拟银行系统存钱问题

    Java利用多线程模拟银行系统存钱问题的完整攻略 1. 问题分析 假设有两个用户账户,分别在同一时间存钱,我们需要通过Java多线程模拟存钱的过程并确保数据的准确性和安全性。 2. 解决方案 为了确保数据的安全,Java使用了synchronized关键字来实现线程同步,同时也使用了wait()和notify()方法来解决线程的等待和调度问题。 Java中可…

    Java 2023年5月18日
    00
  • Java基础之Object类详解

    Java基础之Object类详解 Java中的Object类是所有Java类的祖先类,每个类都继承了Object类的一些方法。在本文中,我们将深入学习Object类,包括其方法以及如何正确重写Object类中的方法。 Object类中的方法 Object类提供了许多有用的方法,如下所示: equals方法 equals方法用于比较两个对象是否相等,默认情况下…

    Java 2023年5月26日
    00
  • 解决Maven本地仓库明明有对应的jar包但还是报找不到的问题

    当我们在使用 Maven 构建项目时,有时会出现 Maven 本地仓库中明明已经有对应的 jar 包,但是在使用时却提示找不到该依赖的情况。这种情况一般是因为 Maven 本地仓库的缓存出现问题,以下是解决该问题的几种方法和步骤: 方法一:清空 Maven 本地仓库缓存 打开命令行窗口并进入到 Maven 本地仓库目录,例如在 Windows 操作系统下,打…

    Java 2023年5月26日
    00
  • java的Hibernate框架报错“ObjectDeletedException”的原因和解决方法

    当使用Java的Hibernate框架时,可能会遇到“ObjectDeletedException”错误。这个错误通常是由于以下原因之一引起的: 对已删除的实体进行操作:如果您尝试对已删除的实体进行操作,则可能会出现此错误。在这种情况下,需要检查实体是否已被删除,并避免对已删除的实体进行操作。 并发访问问题:如果多个线程同时访问同一个实体,则可能会出现此错误…

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