/**
-
雪花算法生成分布式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();
}
}