实现高性能分布式 ID 生成器:Java 雪花算法详解
public class SnowflakeIdGenerator {
// 64位的时间偏移量
private final static long TWEPOCH = 1288834974657L;
// 机器id所占的位数
private final static long WORKER_ID_BITS = 5L;
// 数据标识id所占的位数
private final static long DATA_CENTER_ID_BITS = 5L;
// 序列在id中所占的位数
private final static long SEQUENCE_BITS = 12L;
// 机器ID最大值
private final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
// 数据标识id最大值
private final static long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
// 序列号的掩码,这里为4095 (0b111111111111=0xfff=4095)
private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
// 工作机器ID(0~31)
private long workerId;
// 数据中心ID(0~31)
private long dataCenterId;
// 毫秒内序列(0~4095)
private long sequence = 0L;
// 上次生成ID的时间戳
private long lastTimestamp = -1L;
// 构造函数
public SnowflakeIdGenerator(long workerId, long dataCenterId) {
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0");
}
if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
throw new IllegalArgumentException("dataCenter Id can't be greater than %d or less than 0");
}
this.workerId = workerId;
this.dataCenterId = dataCenterId;
}
// 获得下一个ID
public synchronized long nextId() {
long timestamp = timeGen();
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退了,这是不允许的。
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
// 如果是同一毫秒内重新生成ID,则进行序列号自增
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
// 序列号溢出
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
// 如果是新的一毫秒,则序列号重置
sequence = 0L;
}
// 记录最后一次生成ID的时间戳
lastTimestamp = timestamp;
// 移位并通过按位或运算生成ID
return ((timestamp - TWEPOCH) << (DATA_CENTER_ID_BITS + WORKER_ID_BITS)) |
(dataCenterId << WORKER_ID_BITS) |
(workerId << SEQUENCE_BITS) |
sequence;
}
// 获取当前时间戳
评论已关闭