1:SnowflakeId雪花算法
public class SnowflakeIdUtils {@Getterprivate 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位的IDlong 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 {@Getterprivate 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; // 等待时间前进}// 同一毫秒内生成 IDif (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();}
}