雪花算法源码详解

本源码基于3.1.0版本sharding-jdbc

<dependency>
    <groupId>io.shardingspheregroupId>
    <artifactId>sharding-jdbc-spring-boot-starterartifactId>
    <version>3.1.0version>
dependency>

首先我们要了解雪花算法的结构
雪花算法源码详解_第1张图片第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);
    }
}

你可能感兴趣的:(java,源码,sharding-jdbc)