Java使用雪花算法生成唯一ID的实现示例

 更新时间:2024年07月09日 10:26:04   作者:小筱在线  
雪花算法是 Twitter 开源的一种分布式ID生成算法,其目的是生成全局唯一的 ID,本文主要介绍了Java使用雪花算法生成唯一ID的实现示例,具有一定的参考价值,感兴趣的可以了解一下

雪花算法(Snowflake ID)是 Twitter 开源的一种分布式 ID 生成算法,其目的是生成全局唯一的 ID。该算法的核心思想是将一个 64 位的二进制数字分成几个部分,每个部分表示不同的信息,例如数据中心ID、机器ID、序列号等。这些部分的取值范围可以根据实际情况进行调整。

使用雪花算法生成的 ID 具有以下特点:

  • 全局唯一,ID 不会重复。
  • 按时间有序,新生成的 ID 比旧的 ID 大。
  • 可以在分布式环境下生成,不需要中心节点协调。
  • 高性能,生成 ID 的速度快。

因其具有全局唯一和分布式特性,常被用于互联网应用的分布式系统中,如订单号生成、数据库主键生成等。

具体实现代码如下:

public class Snowflake {

    /** 开始时间戳 (2021-01-01) */
    private final long START_TIMESTAMP = 1609430400000L;

    /** 机器ID所占的位数 */
    private final long WORKER_ID_BITS = 5L;

    /** 数据标识ID所占的位数 */
    private final long DATA_CENTER_ID_BITS = 5L;

    /** 支持的最大机器ID,结果是31 (0B11111) */
    private final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);

    /** 支持的最大数据标识ID,结果是31 (0B11111) */
    private final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);

    /** 序列在ID中占的位数 */
    private final long SEQUENCE_BITS = 12L;

    /** 机器ID向左移12位 */
    private final long WORKER_ID_SHIFT = SEQUENCE_BITS;

    /** 数据标识ID向左移17位(12+5) */
    private final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;

    /** 时间戳向左移22位(5+5+12) */
    private final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;

    /** 支持的最大序列号,结果是4095 (0B111111111111) */
    private final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);

    /** 工作机器ID */
    private final long workerId;

    /** 数据中心ID */
    private final long dataCenterId;

    /** 毫秒内序列号 */
    private long sequence = 0L;

    /** 上次生成ID的时间戳 */
    private long lastTimestamp = -1L;

    /**
     * 构造函数
     * @param workerId 工作机器ID
     * @param dataCenterId 数据中心ID
     */
    public Snowflake(long workerId, long dataCenterId) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException(String.format("WorkerID不能超过%d且不能小于0", MAX_WORKER_ID));
        }
        if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
            throw new IllegalArgumentException(String.format("DataCenterID不能超过%d且不能小于0", MAX_DATA_CENTER_ID));
        }
        this.workerId = workerId;
        this.dataCenterId = dataCenterId;
    }

    /**
     * 生成ID
     * @return long类型的ID
     */
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        // 如果当前时间小于上次生成ID的时间戳,说明系统时钟回退过,抛出异常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("系统时钟回退,拒绝生成ID,上次生成ID的时间戳:%d,当前时间戳:%d",
                    lastTimestamp, timestamp));
        }

        // 如果当前时间等于上次生成ID的时间戳(同一毫秒内),则序列号加1
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                // 如果序列号已经超过最大值,需要等待到下一毫秒再继续生成ID
                timestamp = waitNextMillis(timestamp);
            }
        } else {
            sequence = 0L;
        }

        // 更新上次生成ID的时间戳
        lastTimestamp = timestamp;

        // 生成ID
        return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT) |
                (dataCenterId << DATA_CENTER_ID_SHIFT) |
                (workerId << WORKER_ID_SHIFT) |
                sequence;
    }

    /**
     * 等待下一毫秒
     * @param timestamp 上次生成ID的时间戳
     * @return 下一毫秒的时间戳
     */
    private long waitNextMillis(long timestamp) {
        long nextTimestamp = System.currentTimeMillis();
        while (nextTimestamp <= timestamp) {
            nextTimestamp = System.currentTimeMillis();
        }
        return nextTimestamp;
    }

    // 示例
    public static void main(String[] args) {
        Snowflake snowflake = new Snowflake(1, 1);
        System.out.println(snowflake.nextId());
    }
}

在上述代码中,可以通过调整START_TIMESTAMP、WORKER_ID_BITS、DATA_CENTER_ID_BITS、SEQUENCE_BITS等参数来满足不同的需求,例如支持更多的机器、更高的QPS等。

这是批量生成的ID:

到此这篇关于Java使用雪花算法生成唯一ID的实现示例的文章就介绍到这了,更多相关Java 雪花算法生成唯一ID内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • Java并发统计变量值偏差原因及解决方案

    Java并发统计变量值偏差原因及解决方案

    这篇文章主要介绍了Java并发统计变量值偏差原因及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • java常见log日志的使用方法解析

    java常见log日志的使用方法解析

    本文主要介绍了java常见log日志的使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • 一文快速了解spring boot中的@idempotent注解

    一文快速了解spring boot中的@idempotent注解

    idempotence注解是RESTful API设计中一个重要的概念,它可以保证操作的可靠性和一致性,下面这篇文章主要给大家介绍了关于spring boot中@idempotent注解的相关资料,需要的朋友可以参考下
    2024-01-01
  • 聊聊SpringMVC项目依赖和静态资源导出问题

    聊聊SpringMVC项目依赖和静态资源导出问题

    这篇文章主要介绍了SpringMVC项目依赖和静态资源导出问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • springBoot2.X配置全局捕获异常的操作

    springBoot2.X配置全局捕获异常的操作

    这篇文章主要介绍了springBoot2.X配置全局捕获异常的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • IDEA mybatis-generator逆向工程生成代码

    IDEA mybatis-generator逆向工程生成代码

    这篇文章主要介绍了IDEA mybatis-generator逆向工程生成代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • 解决mybatis plus 驼峰式命名规则问题

    解决mybatis plus 驼峰式命名规则问题

    这篇文章主要介绍了解决mybatis plus 驼峰式命名规则,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • AJAX SpringBoot 前后端数据交互的项目实现

    AJAX SpringBoot 前后端数据交互的项目实现

    本文主要介绍了AJAX SpringBoot 前后端数据交互的项目实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • lombok注解介绍小结

    lombok注解介绍小结

    lombok是一个可以帮助我们简化java代码编写的工具类,这篇文章主要介绍了lombok注解介绍小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • Java 3D入门之基本图形功能 附源码

    Java 3D入门之基本图形功能 附源码

    Java3D API是Sun定义的用于实现3D显示的接口。3D技术是底层的显示技术,Java3D提供了基于Java的上层接口。Java3D把OpenGL和DirectX这些底层技术包装在Java接口中。这种全新的设计使3D技术变得不再繁琐且可以加入到J2SE、J2EE的整套架构,故保证了Java3D技术强大的扩展性
    2021-10-10

最新评论