/**
-
雪花算法生成分布式ID
-
/// 共64位 第1位不使用,242位為時間戳,4352位為工作機器id,53~64 位為序列號
-
/// 可部署1024個節點,每毫秒可產生4096個唯一id
-
參考鏈接:https://blog.csdn.net/yangding_/article/details/52768906
*/
public class IdWorker {/// 工作進程id 5位
private long workerId;
/// 數據中心id 5位
private long datacenterId;
/// 順序 12位,0~4095
private long sequence = 0L;
// 初始時間戳
// 1288834974657 是 (Thu, 04 Nov 2010 01:42:54 GMT) 這一時刻到1970-01-01 00:00:00時刻所經過的毫秒數。
// 41位字節作為時間戳數值的話,大約68年就會用完,
// 假如你2010年1月1日開始開發系統,如果不減去2010年1月1日的時間戳,那么白白浪費40年的時間戳啊!
// 所以減去twepoch 可以讓系統在41位字節作為時間戳的情況下的運行時間更長。1288834974657L可能就是該項目開始成立的時間。
private long twepoch = 1288834974657L;
//長度定義及最大值定義
private long workerIdBits = 5L;
private long datacenterIdBits = 5L;
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long sequenceBits = 12L;// 工作id 左移12位
private long workerIdShift = sequenceBits;
//數據中心id 左移17位
private long datacenterIdShift = sequenceBits + workerIdBits;
//時間戳左移22位
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
//判斷是否已經到達最大序列號
private long sequenceMask = -1L ^ (-1L << sequenceBits);private long lastTimestamp = -1L;
public IdWorker(long workerId, long datacenterId) {
// sanity check for workerId
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}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) {
sequence = (sequence + 1) & sequenceMask;
//如果達到最大值,則等待下一毫秒,序列號從0 開始
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
//重置上一次毫秒數
lastTimestamp = timestamp;
//返回時間戳+工作節點+序列號
return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
}/// 獲取下一毫秒
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}/// 獲取當前時間戳
protected long timeGen() {
return System.currentTimeMillis();
}
}