本文目录导读:

我来详细介绍雪花算法的Java实现。
雪花算法结构
雪花算法的ID由64位二进制组成:
- 1位:符号位(始终为0)
- 41位:时间戳(毫秒级)
- 10位:工作机器ID
- 12位:序列号
基础实现
public class SnowflakeIdGenerator {
// 基础常量
private final long twepoch = 1609459200000L; // 2021-01-01 00:00:00
// 机器ID位数
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
// 序列号位数
private final long sequenceBits = 12L;
// 最大值计算
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
// 位移量
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
// 组件值
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeIdGenerator(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(
String.format("Worker ID must be between 0 and %d", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(
String.format("Datacenter ID must be between 0 and %d", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = timeGen();
// 时钟回拨处理
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset <= 5) {
// 等待时间前进
try {
wait(offset * 100);
} catch (Exception e) {
Thread.yield();
}
timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing for %d milliseconds", offset));
}
} else {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing for %d milliseconds", offset));
}
}
// 同一毫秒内处理序列号
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 序列号已满,等待下一毫秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// 生成ID
return ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift)
| sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
}
增强版实现(推荐)
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
public class SnowflakeIdGeneratorV2 {
private final long twepoch = 1609459200000L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long sequenceBits = 12L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final long workerId;
private final long datacenterId;
private AtomicLong sequence = new AtomicLong(0);
private volatile long lastTimestamp = -1L;
private final ReentrantLock lock = new ReentrantLock();
// 自动获取机器ID
public SnowflakeIdGeneratorV2() {
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getWorkerId(maxWorkerId, datacenterId);
}
public SnowflakeIdGeneratorV2(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(
String.format("Worker ID must be between 0 and %d", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(
String.format("Datacenter ID must be between 0 and %d", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public long nextId() {
long timestamp = timeGen();
lock.lock();
try {
if (timestamp < lastTimestamp) {
// 处理时钟回拨
handleClockBackwards(lastTimestamp - timestamp);
timestamp = timeGen();
}
if (lastTimestamp == timestamp) {
long currentSequence = sequence.incrementAndGet() & sequenceMask;
if (currentSequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
sequence.set(currentSequence);
} else {
sequence.set(0L);
}
lastTimestamp = timestamp;
} finally {
lock.unlock();
}
return ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift)
| sequence.get();
}
private void handleClockBackwards(long offset) {
if (offset > 5) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing for %d milliseconds", offset));
}
try {
Thread.sleep(offset * 10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Thread interrupted while waiting for clock recovery");
}
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
// 自动获取数据中心ID
private long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
if (null != mac) {
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
}
} catch (Exception e) {
id = 1L;
}
return id;
}
// 自动获取工作机器ID
private long getWorkerId(long maxWorkerId, long datacenterId) {
StringBuilder macString = new StringBuilder();
try {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
byte[] mac = networkInterface.getHardwareAddress();
if (mac != null) {
for (byte b : mac) {
macString.append(String.format("%02X", b));
}
break;
}
}
} catch (Exception e) {
// 使用默认值
}
return (macString.toString().hashCode() % (maxWorkerId + 1) + datacenterId) % (maxWorkerId + 1);
}
// 解析ID
public static Map<String, Long> parseId(long id) {
long sequence = id & 0xFFFL;
long workerId = (id >> 12) & 0x1FL;
long datacenterId = (id >> 17) & 0x1FL;
long timestamp = (id >> 22) + 1609459200000L;
Map<String, Long> result = new HashMap<>();
result.put("timestamp", timestamp);
result.put("datacenterId", datacenterId);
result.put("workerId", workerId);
result.put("sequence", sequence);
return result;
}
}
使用示例
public class SnowflakeIdDemo {
public static void main(String[] args) {
// 方式1:手动指定机器ID
SnowflakeIdGenerator generator1 = new SnowflakeIdGenerator(1L, 1L);
long id1 = generator1.nextId();
System.out.println("Generated ID: " + id1);
// 方式2:自动获取机器ID
SnowflakeIdGeneratorV2 generator2 = new SnowflakeIdGeneratorV2();
long id2 = generator2.nextId();
System.out.println("Generated ID: " + id2);
// 解析ID
Map<String, Long> parsed = SnowflakeIdGeneratorV2.parseId(id2);
System.out.println("Parsed ID: " + parsed);
// 批量生成测试
Set<Long> idSet = new HashSet<>(10000);
for (int i = 0; i < 10000; i++) {
long id = generator2.nextId();
if (!idSet.add(id)) {
System.out.println("Duplicate ID found: " + id);
}
}
System.out.println("Generated 10000 unique IDs successfully");
}
}
Spring Boot集成
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;
@Configuration
public class SnowflakeConfig {
@Value("${snowflake.workerId:1}")
private long workerId;
@Value("${snowflake.datacenterId:1}")
private long datacenterId;
@Bean
public SnowflakeIdGeneratorV2 snowflakeIdGenerator() {
return new SnowflakeIdGeneratorV2(workerId, datacenterId);
}
}
// 使用示例
@Service
public class OrderService {
@Autowired
private SnowflakeIdGeneratorV2 snowflakeIdGenerator;
public Long createOrderId() {
return snowflakeIdGenerator.nextId();
}
}
高级特性实现
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class SnowflakeIdPool {
private final BlockingQueue<Long> idPool;
private final SnowflakeIdGeneratorV2 generator;
private volatile boolean running = true;
public SnowflakeIdPool(int poolSize, int workerId, int datacenterId) {
this.idPool = new LinkedBlockingQueue<>(poolSize);
this.generator = new SnowflakeIdGeneratorV2(workerId, datacenterId);
startIdProducer();
}
private void startIdProducer() {
Thread producer = new Thread(() -> {
while (running) {
try {
if (idPool.remainingCapacity() > 0) {
long id = generator.nextId();
idPool.offer(id);
}
Thread.sleep(1);
} catch (Exception e) {
Thread.currentThread().interrupt();
break;
}
}
}, "snowflake-id-producer");
producer.setDaemon(true);
producer.start();
}
public Long getId() {
try {
return idPool.poll(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return generator.nextId();
}
}
public void shutdown() {
this.running = false;
}
}
关键设计要点
- 唯一性保证:时间戳+机器ID+序列号组合
- 高性能:使用位运算和原子操作
- 时钟回拨处理:等待或抛异常
- 线程安全:使用synchronized或Lock
配置建议
# application.yml snowflake: workerId: 1 datacenterId: 1
这个实现适合分布式系统,每秒可生成数百万个唯一ID。