目录
我的其他博客
什么情况下会产生StackOverflowError(栈溢出)和OutOfMemoryError(堆溢出)怎么排查-CSDN博客
谈谈我对HashMap扩容机制的理解及底层实现-CSDN博客
Redis 两种持久化方式 AOF 和 RDB-CSDN博客MySQL中的锁(简单)-CSDN博客
首先雪花算法是一种分布式唯一ID生成算法,它能够在分布式系统中生成全局唯一的ID。雪花算法的特点是简单、高效,且生成的ID呈趋势递增,适用于分布式系统中需要唯一ID的场景。以下是雪花算法的原理和实现细节,用Java语言描述。
雪花算法原理:
-
时间戳(41位): 使用41位来表示当前时间戳,精确到毫秒级。这可以支持约69年的时间范围,但需要注意的是,由于使用的是毫秒级别的时间戳,系统时钟同步是很关键的。
-
机器标识(10位): 用来标识不同的机器。10位的机器标识可以支持1024台不同的机器。
-
序列号(12位): 如果在同一毫秒内产生多个ID,通过序列号来区分。12位的序列号可以支持每台机器每毫秒产生4096个ID。
雪花算法生成ID的步骤:
-
获取当前时间戳,精确到毫秒。
-
将获取到的时间戳左移22位,空出10位来存放机器标识。
-
获取机器标识,将其左移12位,空出12位来存放序列号。
-
获取序列号,如果在当前毫秒内已经产生了4096个ID,则等待下一毫秒再生成。
-
将时间戳、机器标识和序列号进行位运算,得到最终的64位ID。
下面是用Java语言实现
public class SnowflakeIdGenerator {
// 起始的时间戳
private static final long START_TIMESTAMP = 1617264000000L; // 2021-04-01 00:00:00
// 机器标识位数
private static final long WORKER_ID_BITS = 10L;
// 序列号位数
private static final long SEQUENCE_BITS = 12L;
// 最大机器标识
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
// 最大序列号
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
// 机器标识左移位数
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
// 时间戳左移位数
private static final long TIMESTAMP_SHIFT = WORKER_ID_BITS + SEQUENCE_BITS;
// 上次生成ID时的时间戳
private long lastTimestamp = -1L;
// 当前毫秒内的序列号
private long sequence = 0L;
// 当前机器标识
private final long workerId;
public SnowflakeIdGenerator(long workerId) {
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException("Worker ID can't be greater than " + MAX_WORKER_ID + " or less than 0");
}
this.workerId = workerId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds.");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0) {
// 当前毫秒内的序列号用尽,等待下一毫秒
timestamp = waitNextMillis(lastTimestamp);
}
} else {
// 新的毫秒,序列号重置
sequence = 0;
}
lastTimestamp = timestamp;
return ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT) |
(workerId << WORKER_ID_SHIFT) |
sequence;
}
private long waitNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
public static void main(String[] args) {
// 示例:创建一个workerId为1的Snowflake算法ID生成器
SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1);
// 生成10个ID并输出
for (int i = 0; i < 10; i++) {
long id = idGenerator.nextId();
System.out.println("Generated ID: " + id);
}
}
}
这段代码演示了如何使用Java语言实现雪花算法。每个工作节点(机器)需要有一个唯一的workerId。这个算法确保了在同一毫秒内,每个节点的序列号都是唯一的。当序列号达到最大值时(4095),会等待下一毫秒再继续生成。