雪花算法源码详解

6 篇文章 0 订阅
1 篇文章 0 订阅

本源码基于3.1.0版本sharding-jdbc

<dependency>
    <groupId>io.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>3.1.0</version>
</dependency>

首先我们要了解雪花算法的结构
雪花算法id结构第1位是预留位,中间41位是时间戳,中间是机器id (默认是0) ,所以机器之间必须设置不同的wordId。
设置工作id源码如下

	private static long workerId;
    /**
     * Set work process id.
     * 作用设置工作id
     * @param workerId work process id
     */
    public static void setWorkerId(final long workerId) {
    	//校验workId准确性
        Preconditions.checkArgument(workerId >= 0L && workerId < WORKER_ID_MAX_VALUE);
        DefaultKeyGenerator.workerId = workerId;
    }

针对时钟回拨问题,设置最大容忍的毫秒数

    /**
     * Set max tolerate time difference milliseconds.
     *
     * @param maxTolerateTimeDifferenceMilliseconds max tolerate time difference milliseconds
     */
    public static void setMaxTolerateTimeDifferenceMilliseconds(final int maxTolerateTimeDifferenceMilliseconds) {
        DefaultKeyGenerator.maxTolerateTimeDifferenceMilliseconds = maxTolerateTimeDifferenceMilliseconds;
    }

生成唯一的号码

    /**
     * Generate key.
     * 
     * @return key type is @{@link Long}.
     */
    @Override
    public synchronized Number generateKey() {
    	//获取当前时间
        long currentMilliseconds = timeService.getCurrentMillis();
        //判断是否有时钟回拨,有就等待到最后主键生成的时间,然后再获取当前时间,在这里解决时钟回拨问题
        if (waitTolerateTimeDifferenceIfNeed(currentMilliseconds)) {
            currentMilliseconds = timeService.getCurrentMillis();
        }
        //如果毫秒数相同
        if (lastMilliseconds == currentMilliseconds) {
        	//sequence = (sequence + 1)序列值+1
            if (0L == (sequence = (sequence + 1) & SEQUENCE_MASK)) {
            	//获取最新的时间
                currentMilliseconds = waitUntilNextTime(currentMilliseconds);
            }
        } else {
        	//将序列重置为1
            vibrateSequenceOffset();
            sequence = sequenceOffset;
        }
        //更新上一次生成时间
        lastMilliseconds = currentMilliseconds;
        return ((currentMilliseconds - EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (workerId << WORKER_ID_LEFT_SHIFT_BITS) | sequence;
    }
    /**
    *
    */
    @SneakyThrows
    private boolean waitTolerateTimeDifferenceIfNeed(final long currentMilliseconds) {
    	//判断是否产生时钟回拨
        if (lastMilliseconds <= currentMilliseconds) {
            return false;
        }
        //时钟回拨的差值
        long timeDifferenceMilliseconds = lastMilliseconds - currentMilliseconds;
        //是否大于最大容忍时间
        Preconditions.checkState(timeDifferenceMilliseconds < maxTolerateTimeDifferenceMilliseconds, 
                "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", lastMilliseconds, currentMilliseconds);
        //会等待同步到最后一次主键生成lastMilliseconds(上一次的主键生成的时间)
        Thread.sleep(timeDifferenceMilliseconds);
        return true;
    }
    //只有当前时间大于上次的时间才跳出循环,返回时间值
    private long waitUntilNextTime(final long lastTime) {
        long result = timeService.getCurrentMillis();
        while (result <= lastTime) {
            result = timeService.getCurrentMillis();
        }
        return result;
    }
    //将序列重置为1
    private void vibrateSequenceOffset() {
       /**
    	 * byte是8位二进制
    	 * sequenceOffset默认值是0000 0000
    	 * ~sequenceOffset取反运算后是1111 1111
    	 * &1 位与运算后是0000 0001,转换为十进制就是1
    	 */
        sequenceOffset = (byte) (~sequenceOffset & 1);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值