Twitter SnowFlake
說明
第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));
}
}
}