Seata源码解析
Seata-common模块,IdWorker类分析
运算符知识:
- 与运算 & 两位同时为1,结果为1,否则为0
- 或运算 | 参加运算的两个对象只要有一个为1,其值为1
- 异或运算 ^ 参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0
- 取反运算 ~ 对一个二进制数按位取反,即将0变1,1变0
ID生成器,雪花算法
private final long workerIdShift = 12;
private final long twepoch = 1588435200000L;
private final long timestampLeftShift = 22;
public synchronized long nextId() {
//获取当前毫秒数
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format(
"clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
//每一毫秒获取不超过4095个id, 超过在下一毫秒获取
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
//id由三部分组成
return ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
}
ID分三部分组成:
1. (timestamp – twepoch) << timestampLeftShift
当前毫秒时间戳 – 初始化毫秒时间戳 左移 22位
十进制:30149324525 = 1618584524525 – 1588435200000
转换二进制:11100000101000010100010111011101101
左移22位(补22个0):111000001010000101000101110111011010000000000000000000000
2. workerId << workerIdShift 获取机器id 左移12位
public static final int SIZE = 8;
public static long initWorkerId() {
InetAddress address;
try {
address = InetAddress.getLocalHost();
} catch (final UnknownHostException e) {
throw new IllegalStateException("Cannot get LocalHost InetAddress, please check your network!",e);
}
byte[] ipAddressByteArray = address.getAddress();
//机器id由两值相加
return ((ipAddressByteArray[ipAddressByteArray.length - 2] & 0B11) << Byte.SIZE) + (ipAddressByteArray[ipAddressByteArray.length - 1] & 0xFF);
}
ipAddressByteArray 返回本机ip4或ip6字节数组;
0B对应二进制,0x对应十六进制
机器id由两值相加:
- (byte值 & 0B11) << Byte.SIZE;即最大值为 0B11=3, 左移8位:1100000000; 所以最大十进制值:768
- (byte值 & 0xFF) ; 16进制F对应二进制为 1111,所以最大十进制值:255
768 + 255 = 1023,也就是机器id最大不超过1023
workerId << workerIdShift 即:1111111111000000000000
3. sequence
sequence = (sequence + 1) & sequenceMask;
long sequenceMask = -1L ^ (-1L << 12L) 左移12位:
负数用正值的补码形式表达;原码取反变反码,反码加1变成补码
最终二进制为 111111111111,十进制为4095,sequence 最大为4095,否则获取下一个毫秒数,从0开始计算
最终二进制位标识:111000001001101110001011110111010100000000000000000000000 | 1111111111000000000000 | 111111111111
位结构:前41位-时间戳 中间10位-机器id 后12位-自增id
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/221961.html