package com.webmanage.util; import java.util.concurrent.locks.ReentrantLock; /** * Snowflake 雪花算法ID生成器(64位) * 结构:1位符号位 + 41位时间戳 + 5位数据中心 + 5位工作机器 + 12位序列 */ public class SnowflakeIdWorker { private final long twepoch; private final long workerIdBits = 5L; private final long datacenterIdBits = 5L; private final long maxWorkerId = -1L ^ (-1L << workerIdBits); private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private final long sequenceBits = 12L; private final long workerIdShift = sequenceBits; private final long datacenterIdShift = sequenceBits + workerIdBits; private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private final long sequenceMask = -1L ^ (-1L << sequenceBits); private final long workerId; private final long datacenterId; private long sequence = 0L; private long lastTimestamp = -1L; private final ReentrantLock lock = new ReentrantLock(true); /** * @param workerId 工作机器ID (0~31) * @param datacenterId 数据中心ID (0~31) * @param twepochMs 自定义纪元时间(毫秒),建议为系统上线前固定时间戳,默认 2020-01-01 */ public SnowflakeIdWorker(long workerId, long datacenterId, long twepochMs) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException("worker Id can't be greater than " + maxWorkerId + " or less than 0"); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException("datacenter Id can't be greater than " + maxDatacenterId + " or less than 0"); } this.workerId = workerId; this.datacenterId = datacenterId; this.twepoch = twepochMs; } /** * 线程安全生成下一个ID */ public long nextId() { lock.lock(); try { long timestamp = currentTime(); if (timestamp < lastTimestamp) { // 时钟回拨处理:等待到 lastTimestamp long offset = lastTimestamp - timestamp; try { Thread.sleep(offset); } catch (InterruptedException ignored) { } timestamp = currentTime(); if (timestamp < lastTimestamp) { // 如果仍小于,强制使用 lastTimestamp timestamp = lastTimestamp; } } if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { // 同毫秒内序列溢出,等待下一毫秒 timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } finally { lock.unlock(); } } private long tilNextMillis(long lastTimestamp) { long timestamp = currentTime(); while (timestamp <= lastTimestamp) { timestamp = currentTime(); } return timestamp; } private long currentTime() { return System.currentTimeMillis(); } }