左移5位 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11100000
[-1] 的补码 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
异或 ----------------------------------------------------------------------- ^
结果的补码 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00011111 (十进制数 2^0 + 2^1 + 2^2 + 2^3 + 2^4 = 31)
这样就能计算出 5 bit 能表示的最大数值 n , n 为整数并且 0 <= n <= 31 ,即 0、1、2、3...31 。 Worker ID 和 Data Center ID 部分的最大值就是运用这种组合运算得出的。
用固定位的最大值作为Mask避免溢出:
Snowflake 算法中有这样的代码:
var sequence = 0L
......
private val sequenceBits = 12L
// 这里失掉的是sequence的最大值4095
private val sequenceMask = -1L ^ (-1L << sequenceBits)
......
sequence = (sequence + 1) & sequenceMask
最后这个算子其实就是 sequence = (sequence + 1) & 4095 ,假定 sequence 以后值为 4095 ,推演一下计算进程:
* [4095] 的补码 00000000 00000000 00000000 00000000 00000000 00000000 00000111 11111111
[sequence + 1] 的补码 00000000 00000000 00000000 00000000 00000000 00000000 00001000 00000000
按位与 ----------------------------------------------------------------------- &
计算结果 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 (十进制数:0)
可以编写一个 main 办法验证一下:
public static void main(String[] args) {
int mask = 4095;
System.out.println(0 & mask); // 0
System.out.println(1 & mask); // 1
System.out.println(2 & mask); // 2
System.out.println(4095 & mask); // 4095
System.out.println(4096 & mask); // 0
System.out.println(4097 & mask); // 1
}
也就是 x = (x + 1) & (-1L ^ (-1L << N)) 能保证最终失掉的 x 值不会超过 N ,这是应用了按位与中的"取指定位"的特性。
Snowflake算法完成源码剖析
Snowflake 虽然用 Scala 言语编写,语法其实和 Java 差不多,当成 Java 代码这样阅读就行,下面阅读代码的时分会跳过一些日志记载和度量统计的逻辑。先看 IdWorker.scala 的属性值:
// 定义基准纪元值,这个值是北京时间2010-11-04 09:42:54,估量就是2010年终版提交代码时分定义的一个时间戳
val twepoch = 1288834974657L
// 初始化序列号为0
(责任编辑:admin)