1:SnowflakeId雪花算法
public class SnowflakeIdUtils {
@Getter
private static final SnowflakeIdUtils instance = new SnowflakeIdUtils(0, 0);
/**
* 机器id所占的位数
*/
private final long workerIdBits = 5L;
/**
* 数据标识id所占的位数
*/
private final long datacenterIdBits = 5L;
/**
* 工作机器ID(0~31)
*/
private final long workerId;
/**
* 数据中心ID(0~31)
*/
private final long datacenterId;
/**
* 毫秒内序列(0~4095)
*/
private long sequence = 0L;
/**
* 上次生成ID的时间截
*/
private long lastTimestamp = -1L;
/**
* 构造函数
*
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
private SnowflakeIdUtils(long workerId, long datacenterId) {
long maxWorkerId = ~(-1L << workerIdBits);
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
long maxDatacenterId = ~(-1L << datacenterIdBits);
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 测试
*/
public static void main(String[] args) {
long st = System.currentTimeMillis();
for (int i = 0; i < 4096000; i++) {
SnowflakeIdUtils.getInstance().nextId();
}
long ent = System.currentTimeMillis();
System.out.println("耗时=>{}" + (ent - st) + " 毫秒");
}
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId
*/
private synchronized long getSnowflakeId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的,则进行毫秒内序列
long sequenceBits = 12L;
if (lastTimestamp == timestamp) {
//生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
long sequenceMask = ~(-1L << sequenceBits);
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
long datacenterIdShift = sequenceBits + workerIdBits;
long epoch = 1420041600000L;
return ((timestamp - epoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << sequenceBits) | sequence;
}
public String nextId() {
return LocalDate.now().toString().replace("-", "") + getSnowflakeId();
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
*
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
*
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
}
2:百度UidGenerator
public class UidGeneratorUtils {
@Getter
private static final UidGeneratorUtils instance = new UidGeneratorUtils(0);
// 起始时间戳(2016-05-05 00:00:00)
private final static long START_STAMP = 1462272000000L;
// 序列号位数
private final static long SEQUENCE_BIT = 12;
// 工作节点位数
private final static long WORKER_BIT = 10;
// 掩码(用于取低 n 位)
private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BIT);
// 最大值
private final static long MAX_WORKER_ID = ~(-1L << WORKER_BIT);
// 工作节点 ID(需确保分布式环境中唯一)
private final long workerId;
// 毫秒内序列号(从 0 开始)
private long sequence = 0L;
// 上一次时间戳
private long lastTimestamp = -1L;
/**
* 构造函数
*
* @param workerId 工作节点 ID(0~1023)
*/
public UidGeneratorUtils(long workerId) {
if (workerId < 0 || workerId > MAX_WORKER_ID) {
throw new IllegalArgumentException("Worker ID 必须在 0~" + MAX_WORKER_ID + " 之间");
}
this.workerId = workerId;
}
/**
* 测试
*/
public static void main(String[] args) {
long st = System.currentTimeMillis();
for (int i = 0; i < 4096000; i++) {
System.out.println(getInstance().nextId());
}
long ent = System.currentTimeMillis();
System.out.println("耗时=>{}" + (ent - st) + " 毫秒");
}
/**
* 生成 ID
*
* @return 64 位 long 型 ID
*/
public synchronized long nextId() {
long timestamp = timeGen();
// 时间回拨处理
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset > 5) { // 允许最多 5ms 的回拨
throw new RuntimeException("时钟回拨,拒绝生成 ID。回拨时间:" + offset + "ms");
}
timestamp = lastTimestamp; // 等待时间前进
}
// 同一毫秒内生成 ID
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp); // 等待下一毫秒
}
} else {
sequence = 0; // 新毫秒,重置序列号
}
lastTimestamp = timestamp;
// 拼接 ID:符号位(0) + 时间戳 + 工作节点 ID + 序列号
return (timestamp - START_STAMP) << (WORKER_BIT + SEQUENCE_BIT) | (workerId << SEQUENCE_BIT) | sequence;
}
/**
* 等待到下一毫秒
*
* @param lastTimestamp 上一次时间戳
* @return 当前时间戳
*/
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 获取当前时间戳
*
* @return 毫秒级时间戳
*/
private long timeGen() {
return System.currentTimeMillis();
}
}