请编写一个以雪花算法为基础的id生成器
时间: 2023-06-05 11:08:04 浏览: 112
好的,关于您的问题,以下是一个以雪花算法为基础的id生成器的示例代码,供您参考:
```java
public class IdGenerator {
// 起始的时间戳,用于计算时间戳部分的值
private final static long START_TIMESTAMP = 1596211200000L; // 2020-08-01 00:00:00
// 每一部分占用的位数
private final static long DATA_CENTER_ID_BITS = 5; // 数据中心id所占的位数
private final static long WORKER_ID_BITS = 5; // 工作机器id所占的位数
private final static long SEQUENCE_BITS = 12; // 序列号所占的位数
// 每一部分的最大值
private final static long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
private final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
// 每一部分向左的位移数
private final static long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;
private final static long TIMESTAMP_LEFT_SHIFT = DATA_CENTER_ID_SHIFT + DATA_CENTER_ID_BITS;
// 数据中心ID
private long dataCenterId;
// 工作机器ID
private long workerId;
// 序列号
private long sequence = 0L;
// 上次生成ID的时间截
private long lastTimestamp = -1L;
public IdGenerator(long dataCenterId, long workerId) {
if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATA_CENTER_ID or less than 0");
}
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException("workerId can't be greater than MAX_WORKER_ID or less than 0");
}
this.dataCenterId = dataCenterId;
this.workerId = workerId;
}
/**
* 生成下一个ID
* @return id
*/
public synchronized long nextId() {
long timestamp = timeGen();
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过,这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
// 如果是同一时间生成的,则进行序列号累加
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & MAX_SEQUENCE;
// 溢出处理
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
// 上次生成ID的时间截
lastTimestamp = timestamp;
// 移位并通过或运算拼到一起组成64位的ID
return ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT) |
(dataCenterId << DATA_CENTER_ID_SHIFT) |
(workerId << WORKER_ID_SHIFT) |
sequence;
}
/**
* 等待下一个时间戳的到来
* @param lastTimestamp 上次生成ID的时间截
* @return 下一个时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 获取当前的时间戳
* @return 当前的时间戳
*/
protected long timeGen() {
return System.currentTimeMillis();
}
}
```
这个id生成器可以生成64位长的唯一id,其中包括以下几个部分:
1. 42位的时间戳,精确到毫秒,可以使用约69年
2. 5位的数据中心id
3. 5位的工作机器id
4. 12位的序列号,支持单机每毫秒最多产生4096个id(当序列号为0时,说明一个毫秒内id已经用完,需要等到下一个毫秒)
可以根据业务需要调整每一部分的位数和最大值。
请注意,这里提供的id生成器只是供参考,实际使用时需要根据具体业务情况进行调整和优化。
阅读全文