Snowflake算法是Twitter开源的分布式ID生成算法,它可以生成唯一的64位ID,其中包含了时间戳、机器ID和序列号。下面是使用Java语言实现Snowflake算法的代码:
public class SnowflakeIdWorker {
public static void main(String[] args) {
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1L);
// 生成10个ID
for (int i = 0; i < 10; i++) {
long id = idWorker.nextId();
System.out.println(id);
}
}
// 时间戳占用的位数
private static final long TIMESTAMP_BITS = 41L;
// 机器ID占用的位数
private static final long WORKER_ID_BITS = 10L;
// 序列号占用的位数
private static final long SEQUENCE_BITS = 12L;
// 最大的机器ID,1023
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
// 最大的序列号,4095
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
// 时间戳的左移位数,22
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
// 机器ID的左移位数,12
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
// 上次生成ID的时间戳
private long lastTimestamp = -1L;
// 序列号
private long sequence = 0L;
// 机器ID
private final long workerId;
// 构造函数
public SnowflakeIdWorker(long workerId) {
if (workerId < 0 || workerId > MAX_WORKER_ID) {
throw new IllegalArgumentException(String.format("workerId can't be greater than %d or less than 0", MAX_WORKER_ID));
}
this.workerId = workerId;
}
// 生成ID的方法
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
// 如果当前时间小于上次生成ID的时间戳,则说明系统时钟回退过,需要等待时间追上上次的时间戳
if (timestamp < lastTimestamp) {
try {
wait(lastTimestamp - timestamp);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
timestamp = System.currentTimeMillis();
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) & MAX_SEQUENCE;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID格式为:时间戳-机器ID-序列号
return ((timestamp << TIMESTAMP_SHIFT) | (workerId << WORKER_ID_SHIFT) | sequence);
}
// 等待时间追上上次的时间戳
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}
上述代码中,使用SnowflakeIdWorker类生成了10个分布式ID。在构造函数中指定机器ID,调用nextId方法可以生成一个唯一的ID。这个ID由三个部分组成:时间戳、机器ID和序列号。其中时间戳占用了41位,可以支持69年的时间戳;机器ID占用了10位,可以支持1024台机器;序列号占用了12位,可以在同一毫秒内生成4096个ID。生成的ID是一个64位的long类型数据,可以在分布式系统中唯一标识一个对象。