文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java使用雪花id生成算法详解

2022-12-20 12:00

关注

什么是雪花算法

雪花算法的本质为生成一个64位长度的具有自增性的分布式全局唯一id。在64bits中,会对不同段的位进行划分。可分为:

位段详解

优点

问题

依赖服务器时间。若服务器时钟回拨,可能会导致生成的id重复。可在代码中新增lastTimeMillis字段,在获取nextId时根据系统当前时间进行判断解决。

但若不进行持久化处理,服务重启后发生时钟回拨依旧会出现重复问题。

实际应用

具体实现


public class SnowflakeUtils {
    // ============================== Basic field ==============================//
    // Datacenter id
    private long datacenterId;
    // Worker id
    private long workerId;
    // Increment sequence
    private long sequence;
    // ============================== Bits ==============================//
    // Bits of datacenter id
    private long datacenterIdBits;
    // Bits of worker id
    private long workerIdBits;
    // Bits of sequence
    private long sequenceBits;
    // ============================== Largest ==============================//
    // Largest datacenter id
    private long largestDatacenterId;
    // Largest worker id
    private long largestWorkerId;
    // Largest sequence
    private long largestSequence;
    // ============================== Shift ==============================//
    // Left shift num of worker id
    private long workerIdShift;
    // Left shift num of datacenter id
    private long datacenterIdShift;
    // Left shift num of timestamp
    private long timestampShift;
    // ============================== Other ==============================//
    // Epoch
    private long epoch;
    // The timestamp that last get snowflake id
    private long lastTimestamp;
    // ============================== End ==============================//
    public SnowflakeUtils(long dataCenterId, long workerId) {
        // Default epoch: 2022-07-22 00:00:00
        this(1658419200000L, -1L, dataCenterId, workerId, 5L, 5L, 5L);
    }
    public SnowflakeUtils(long epoch, long lastTimestamp, long datacenterId, long workerId,
        long datacenterIdBits, long workerIdBits, long sequenceBits) {
        this.epoch = epoch;
        this.lastTimestamp = lastTimestamp;
        this.datacenterId = datacenterId;
        this.workerId = workerId;
        this.sequence = 0L;
        this.datacenterIdBits = datacenterIdBits;
        this.workerIdBits = workerIdBits;
        this.sequenceBits = sequenceBits;
        this.largestDatacenterId = ~(-1L << datacenterIdBits);
        this.largestWorkerId = ~(-1L << workerIdBits);
        this.largestSequence = ~(-1L << sequenceBits);
        if (datacenterId > largestDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(
                String.format("The datacenter id param can't be greater than %s or less than 0",
                    largestDatacenterId));
        }
        if (workerId > largestWorkerId || workerId < 0) {
            throw new IllegalArgumentException(
                String.format("The worker id param can't be greater than %s or less than 0",
                    largestWorkerId));
        }
        this.workerIdShift = sequenceBits;
        this.datacenterIdShift = workerIdShift + workerIdBits;
        this.timestampShift = datacenterIdShift + datacenterIdBits;
    }
    
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();
        // 若时钟回退
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                "System clock moved backward, cannot to generate snowflake id");
        }
        // 若当前毫秒内多次生成雪花id
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & largestSequence;
            // 序列溢出
            if (sequence == 0) {
                timestamp = waitUntilNextMilli(timestamp);
            }
        }
        // 若当前毫秒内首次生成雪花id
        else {
            sequence = 0L;
        }
        // 更新获取雪花id的时间戳
        lastTimestamp = timestamp;
        // 生成雪花id (通过位或运算符进行拼接)
        return ((timestamp - epoch) << timestampShift) // 时间戳段
            | (datacenterId << datacenterIdShift) // 机器码段
            | (workerId << workerIdShift) // 机器码段
            | sequence; // 自增序列段
    }
    
    private long waitUntilNextMilli(long lastTimestamp) {
        long currentTimeMillis;
        do {
            currentTimeMillis = System.currentTimeMillis();
        }
        while (currentTimeMillis <= lastTimestamp);
        return currentTimeMillis;
    }
    
    public static SnowflakeUtils getInstance(long dataCenterId, long workerId) {
        return new SnowflakeUtils(dataCenterId, workerId);
    }
}

到此这篇关于Java使用雪花id生成算法详解的文章就介绍到这了,更多相关Java雪花id生成算法内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯