雪花算法简介

SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id

1c423e167fe24b91bf617738e6a48cfe.png

  • 1位,不用。二进制中最高位为1的都是负数,但是生成的id都是正数,所以这个最高位固定是0

  • 41位,用来记录时间戳(毫秒)。

    • 41位可以表示241-1个数字,

    • 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 241 - 1,减1是因为可表示的数值范围是从0开始算的,而不是1。

    • 也就是说41位可以表示241 - 1个毫秒的值,转化成单位年则是241 - 1 / (1000 * 60 * 60 * 24 * 365) = 69年

  • 10位,用来记录工作机器id。

    • 可以部署在210 = 1024个节点,包括5位datacenterId5位workerId

    • 5位(bit)可以表示的最大正整数是25 - 1 = 31,即可以用0、1、2、3、....31这32个数字,来表示不同的datecenterId或workerId

  • 12位,序列号,用来记录同毫秒内产生的不同id。

    • 12位(bit)可以表示的最大正整数是212 - 1 = 4095,即可以用0、1、2、3、....4095这4096个数字,来表示同一机器同一时间截(毫秒)内产生的4096个ID序号,减1是因为可表示的数值范围是从0开始算的,而不是1。

 直接上代码

/**
 * 雪花算法
 */
public class SnowFlake {
    /**
     * 这里需要记录最后一次生成ID的时间,因为同一毫秒内,可能会生成多个ID,记录后可以用来做比对
     */
    private long lastTime = -1L;
    /**
     * 初始时间,因为时间占41位,所以可以从这个时间开始,差不多使用69年
     */
    private long startTime = System.currentTimeMillis();
    /**
     * 机房ID,占5位,因此最多能够对32个机房有效
     */
    private long dataCenterId;
    /**
     * 机器ID,占5位,因此最多能够对32个机器有效
     */
    private long workId;
    /**
     * 序列号,占12位,因此在一毫秒内最多生成2^12 = 4096个序列号
     */
    private long sequence;


    public SnowFlake(long dataCenterId, long workId, long sequence){
        //机房ID最小值为0,最大值为31
        if(dataCenterId > 31 || dataCenterId < 0){
            throw new IllegalArgumentException("机房ID必须>=0且<=31,当前使用机房ID:" + dataCenterId);
        }
        if(workId > 31 || workId < 0){
            throw new IllegalArgumentException("机器ID必须>=0且<=31,当前使用机器ID:" + workId);
        }
        this.dataCenterId = dataCenterId;
        this.workId = workId;
        this.sequence = sequence;
    }

    public long generateId(){
        long time = System.currentTimeMillis(); //获取系统当前时间
        if(time < lastTime){//防止时间回拨,必须手动将时间拨回
            throw new RuntimeException("时间回拨");
        }
        if(time == lastTime){//同一时间段内,生成多个ID
            //按位与操作符所得结果最大值不会超过参与运算的最小操作数,这里不能超过4096
            sequence = (sequence + 1) & 4095;
            if(sequence == 0){//如果计数重新归0,表示该毫秒内,ID生成的数量已满
                //CPU空转1毫秒
                while ((time = System.currentTimeMillis()) == lastTime);
            }
        } else {
            sequence = 0;
        }
        //时间本身占41位,但是需要向左移动22位才能在指定的位置上
        //机房ID占5位,但是需要向左移动17位才能在指定的位置上
        //机器ID占5位,但是需要向左移动12位才能在指定的位置上
        long id = (time - startTime) << 22 | dataCenterId << 17 | workId << 12 | sequence;
        lastTime = time;
        return id;
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值