请写一段雪花算法的实现代码并且解释
时间: 2024-04-29 20:23:00 浏览: 48
雪花算法java版实现
5星 · 资源好评率100%
雪花算法也称为Twitter雪花算法,是一种分布式ID生成算法,可以产生全局唯一的ID。它的核心思想是,将64位的ID分成不同的部分,其中时间戳占用了42位,可以精确到毫秒级别;数据中心ID和机器ID分别占用了5位和12位,可以表示31个数据中心和每个数据中心下的4095台机器;序列号占用了10位,可以表示每台机器每毫秒的最大并发数为1024。
下面是雪花算法的Java实现代码:
```java
public class SnowflakeIdWorker {
// 数据中心ID和机器ID
private long datacenterId;
private long machineId;
// 序列号
private long sequence = 0L;
// 时间戳
private long lastTimestamp = -1L;
// 时间戳占用位数
private final static long timestampBits = 42L;
// 数据中心ID占用位数
private final static long datacenterIdBits = 5L;
// 机器ID占用位数
private final static long machineIdBits = 12L;
// 序列号占用位数
private final static long sequenceBits = 10L;
// 最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final static long maxMachineId = -1L ^ (-1L << machineIdBits);
private final static long maxSequence = -1L ^ (-1L << sequenceBits);
// 时间戳左移位数
private final static long timestampShift = sequenceBits + machineIdBits + datacenterIdBits;
// 数据中心ID左移位数
private final static long datacenterIdShift = sequenceBits + machineIdBits;
// 机器ID左移位数
private final static long machineIdShift = sequenceBits;
// 构造函数
public SnowflakeIdWorker(long datacenterId, long machineId) {
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException("Datacenter ID can't be greater than " + maxDatacenterId + " or less than 0");
}
if (machineId > maxMachineId || machineId < 0) {
throw new IllegalArgumentException("Machine ID can't be greater than " + maxMachineId + " or less than 0");
}
this.datacenterId = datacenterId;
this.machineId = machineId;
}
// 生成ID
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & maxSequence;
if (sequence == 0L) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return (timestamp << timestampShift) |
(datacenterId << datacenterIdShift) |
(machineId << machineIdShift) |
sequence;
}
// 等待下一毫秒
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}
```
在上面的代码中,我们首先定义了一些常量,包括时间戳占用位数、数据中心ID占用位数、机器ID占用位数、序列号占用位数等等。然后在构造函数中检查数据中心ID和机器ID是否合法,如果不合法则抛出异常。在生成ID时,首先获取当前时间戳,如果时间戳小于上一次生成ID的时间戳,则抛出异常;如果时间戳等于上一次生成ID的时间戳,则递增序列号,如果序列号达到最大值,则等待下一毫秒;如果时间戳大于上一次生成ID的时间戳,则序列号重置为0。最后将时间戳、数据中心ID、机器ID和序列号按位或起来得到ID。在等待下一毫秒时,我们使用了一个循环来等待,直到当前时间戳大于上一次生成ID的时间戳。
阅读全文