/// 工作进程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();
}
}