+180
@@ -0,0 +1,180 @@
|
||||
package com.jy.framework.common.utils;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
|
||||
public class SnowflakeIdGenerator {
|
||||
// ====================== 配置参数 ======================
|
||||
/** 开始时间戳 (2024-01-01 00:00:00),可自定义,减少ID长度 */
|
||||
private static final long START_TIMESTAMP = 1704067200000L;
|
||||
|
||||
/** 机器ID所占的位数 (最多10位,支持1024个节点) */
|
||||
private static final long WORKER_ID_BITS = 10L;
|
||||
|
||||
/** 序列号所占的位数 (最多12位,支持4096个/毫秒) */
|
||||
private static final long SEQUENCE_BITS = 12L;
|
||||
|
||||
// ====================== 位移计算 ======================
|
||||
/** 机器ID左移位数 (12位) */
|
||||
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
|
||||
|
||||
/** 时间戳左移位数 (10+12=22位) */
|
||||
private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
|
||||
|
||||
/** 序列号的最大值 (4095) */
|
||||
private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
|
||||
|
||||
// ====================== 全局变量 ======================
|
||||
/** 机器ID (0-1023) */
|
||||
private final long workerId;
|
||||
|
||||
/** 序列号 (0-4095) */
|
||||
private long sequence = 0L;
|
||||
|
||||
/** 上一次生成ID的时间戳 */
|
||||
private long lastTimestamp = -1L;
|
||||
|
||||
// ====================== 单例实例 ======================
|
||||
private static volatile SnowflakeIdGenerator INSTANCE;
|
||||
|
||||
/**
|
||||
* 私有构造器,初始化机器ID(自动计算,也可手动指定)
|
||||
*
|
||||
* @param workerId 机器ID (0-1023)
|
||||
* @throws IllegalArgumentException 机器ID超出范围时抛出
|
||||
*/
|
||||
private SnowflakeIdGenerator(long workerId) {
|
||||
// 校验机器ID范围
|
||||
long maxWorkerId = ~(-1L << WORKER_ID_BITS);
|
||||
if (workerId < 0 || workerId > maxWorkerId) {
|
||||
throw new IllegalArgumentException(String.format("Worker ID 必须在 0 到 %d 之间", maxWorkerId));
|
||||
}
|
||||
this.workerId = workerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例实例(自动计算机器ID)
|
||||
*
|
||||
* @return 雪花算法生成器实例
|
||||
*/
|
||||
public static SnowflakeIdGenerator getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (SnowflakeIdGenerator.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new SnowflakeIdGenerator(calculateWorkerId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动指定机器ID获取实例(适合分布式部署时手动分配节点ID)
|
||||
*
|
||||
* @param workerId 机器ID (0-1023)
|
||||
* @return 雪花算法生成器实例
|
||||
*/
|
||||
public static SnowflakeIdGenerator getInstance(long workerId) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (SnowflakeIdGenerator.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new SnowflakeIdGenerator(workerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成下一个ID(核心方法,线程安全)
|
||||
*
|
||||
* @return 有序、唯一的Long类型ID
|
||||
* @throws RuntimeException 时钟回拨时抛出(避免ID重复)
|
||||
*/
|
||||
public synchronized long nextId() {
|
||||
long currentTimestamp = System.currentTimeMillis();
|
||||
|
||||
// 检查时钟回拨(关键:避免ID重复)
|
||||
if (currentTimestamp < lastTimestamp) {
|
||||
throw new RuntimeException(
|
||||
String.format("时钟回拨检测!拒绝生成ID,上一次时间:%d,当前时间:%d", lastTimestamp, currentTimestamp));
|
||||
}
|
||||
|
||||
// 同一毫秒内,序列号递增
|
||||
if (currentTimestamp == lastTimestamp) {
|
||||
sequence = (sequence + 1) & SEQUENCE_MASK;
|
||||
// 同一毫秒内序列号用尽,等待下一毫秒
|
||||
if (sequence == 0) {
|
||||
currentTimestamp = waitNextMillis(lastTimestamp);
|
||||
}
|
||||
} else {
|
||||
// 不同毫秒,序列号重置为0
|
||||
sequence = 0L;
|
||||
}
|
||||
|
||||
// 更新最后生成ID的时间戳
|
||||
lastTimestamp = currentTimestamp;
|
||||
|
||||
// 组合ID:时间戳 + 机器ID + 序列号
|
||||
return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT) | (workerId << WORKER_ID_SHIFT)
|
||||
| sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待下一毫秒,直到获取新的时间戳
|
||||
*
|
||||
* @param lastTimestamp 上一次生成ID的时间戳
|
||||
* @return 新的时间戳
|
||||
*/
|
||||
private long waitNextMillis(long lastTimestamp) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
while (timestamp <= lastTimestamp) {
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动计算机器ID(基于网卡+进程ID,避免手动配置)
|
||||
*
|
||||
* @return 0-1023之间的机器ID
|
||||
*/
|
||||
private static long calculateWorkerId() {
|
||||
try {
|
||||
// 第一步:获取网卡MAC地址的哈希值
|
||||
InetAddress address = InetAddress.getLocalHost();
|
||||
long macHash = NetworkInterface.getByInetAddress(address).getHardwareAddress()[0] & 0xFF;
|
||||
|
||||
// 第二步:获取进程ID(避免同一机器多进程冲突)
|
||||
String processName = ManagementFactory.getRuntimeMXBean().getName();
|
||||
long pid = Long.parseLong(processName.split("@")[0]);
|
||||
|
||||
// 组合并取模,确保在0-1023之间
|
||||
return (macHash + pid) % (~(-1L << WORKER_ID_BITS));
|
||||
} catch (Exception e) {
|
||||
// 异常时返回随机数(生产环境建议手动指定机器ID)
|
||||
return (long)(Math.random() * (~(-1L << WORKER_ID_BITS)));
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 测试用例 ======================
|
||||
public static void main(String[] args) {
|
||||
// 测试生成10个ID,验证有序性和唯一性
|
||||
SnowflakeIdGenerator generator = SnowflakeIdGenerator.getInstance();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
long id = generator.nextId();
|
||||
System.out.println("生成的ID:" + id);
|
||||
}
|
||||
|
||||
// 多线程测试(验证线程安全)
|
||||
Runnable task = () -> {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
System.out.println(Thread.currentThread().getName() + " -> " + generator.nextId());
|
||||
}
|
||||
};
|
||||
new Thread(task, "线程1").start();
|
||||
new Thread(task, "线程2").start();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user