demo系列-分布式ID-雪花算法
说明
第1位:不使用
第[2,42]:毫秒级时间。可使用69年
第[43,47]:datacenterId
第[48,52]:workerId
[43,52]十位最多部署1024个节点
第[53,64]:毫秒内的计数/序列号
Long的值
0, 时间截=当前-开始, 数据中心Id+机器Id,12位序列号
代码
public class Snowflake {
/*
第1位:不使用
第[2,42]:毫秒级时间。可使用69年
第[43,47]:dataCenterId
第[48,52]:workerId
[43,52]十位最多部署1024个节点
第[53,64]:毫秒内的计数/序列号
1. 开始时间戳
2. 所占位数:时间截、数据中心、机器、序列号
3. 最大值:时间截、数据中心、机器、序列号
4. 移位:
5. 存储位:时间截,机器Id,数据中心Id,序列号Id
*/
// 1. 开始时间戳
private final long epoch = System.currentTimeMillis();
// 2. 所占位数
private final long[] bits = {41L, 5L, 5L, 12L};
// 3. 最大值
private final long[] max = {-1L ^ (-1L << bits[0]), -1L ^ (-1L << bits[1]), -1L ^ (-1L << bits[2]), -1L ^ (-1L << bits[3])};
// 4. 移位
private final long[] move = {bits[1] + bits[2] + bits[3], bits[2] + bits[3], bits[3]};
// 5. 对应域的当前值
private long timestamp = -1L;
private long dataCenterId;
private long workerId;
private long sequence = 0L;
/**
* 0表示时间截,1表示数据中心,2表示机器Id,3表示序列号。使用枚举量比较好,此处省事
* @param index
* @param cur
* @return
*/
private boolean checkRange(int index, long cur) {
if (cur < 0 || cur > max[index]) {
return true;
}
return false;
}
public Snowflake(long dataCenterId, long workerId) {
if (checkRange(1, dataCenterId)) {
String info = String.format("数据中心Id的范围应为:[0, {}]", max[1]);
throw new IllegalArgumentException(info + ";当前为:" + dataCenterId);
}
if (checkRange(2, workerId)) {
String info = String.format("机器Id的范围应为:[0, {}]", max[2]);
throw new IllegalArgumentException(info + ";当前为:" + workerId);
}
this.dataCenterId = dataCenterId;
this.workerId = workerId;
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < this.timestamp) {
// 当前时间 < 上一次时间。系统时钟回退,应抛出异常
String info = String.format("系统时钟回退,拒绝生成时间截:{},上一次时间截:{}", timestamp - epoch, this.timestamp - epoch);
throw new RuntimeException(info);
} else if (timestamp == this.timestamp) {
// 同一毫秒内生成,则序列号升序
sequence = (sequence + 1) % max[3];
if (sequence == 0) {
System.out.println("max:" + max[3]);
// 序列溢出,比如同一毫秒内生成id过多,超出序列号最大值12的4096-1=4095
timestamp = nextMills(this.timestamp);
}
} else {
sequence = 0L;
}
// 更新this.timestamp
this.timestamp = timestamp;
return ((timestamp - epoch) << move[0] | dataCenterId << move[1] | workerId << move[2] | sequence);
}
protected long timeGen() {
return System.currentTimeMillis();
}
protected long nextMills(long last) {
long timestamp = timeGen();
while (timestamp <= last) {
timestamp = timeGen();
}
return timestamp;
}
public static void main(String[] args) {
Snowflake snowflake = new Snowflake(0, 0);
for (int i = 0; i < 10000; ++i) {
long id = snowflake.nextId();
System.out.println(Long.toBinaryString(id));
}
}
}