本源码基于3.1.0版本sharding-jdbc
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
首先我们要了解雪花算法的结构
第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);
}
}