其实雪花算法比较简单,可能称不上什么算法,就是一种构造UID的方法。
点1:UID是一个long类型的41位时间戳,10位存储机器码,12位存储序列号。
点2:时间戳的单位是毫秒,可以同时链接1024台机器,每台机器每毫秒可以使用4096个序列号,我们会给生成id上一个同步锁,阻塞住其他线程的访问。
点3:利用掩码我们可以检测序列是否溢出,如果溢出的话,就强制等待到下一毫秒。
点4:对了看文章的时候发现,前端js的long类型是2的53次方,而java是2的63次方,要注意溢出哦。
/** * @author hardstone * @since 29 July 2023(1690603385473) */ public class
SnowFlakes { //开始的时间戳 private final long start = 1690603385473L; //机器标识长度5位
private final long machineIdBits = 5L; //机器集群标识长度5位 private final long
centerIdBits= 5L; //序列标识所占位数12位 private final long sequenceBits = 12L; //机器标识最大值
private final long maxMachineId = -1L ^ (-1L << machineIdBits); //机器集群标识最大值
private final long maxCenterId = -1L ^ (-1L << centerIdBits); //序列标识的最大值 private
final long sequenceMask = -1L ^ (-1L << sequenceBits); //机器标识左移长度 private final
long machineIdShift = sequenceBits; //机器集群标识左移长度 private final long
centerIdShift= sequenceBits + machineIdBits; //时间戳左移长度 private final long
timeStampIdShift= sequenceBits + machineIdBits + centerIdBits; //序列Id private
long sequence = 0L; //机器Id private long machineId; //机器集群Id private long
centerId; //时间戳 private long lastTimeStamp = -1L; public SnowFlakes(long
machineId, long centerId) { if (machineId > maxMachineId || machineId < 0) {
throw new IllegalArgumentException(String.format("WorkerId should be between 0
and 31")); } if (centerId > maxCenterId || centerId < 0) { throw new
IllegalArgumentException(String.format("CenterId should be between 0 and 31"));
} } public synchronized long nextId() { long timeStamp = System.
currentTimeMillis(); //时间回滚现象 if (timeStamp < lastTimeStamp) { throw new
RuntimeException( String.format("Time gone backwards!") ); } if (lastTimeStamp
== timeStamp) { sequence = (sequence + 1) & sequenceMask; //如果序列分配完了 if (
sequence== 0) { timeStamp = getNextMillis(lastTimeStamp); } } else { sequence =
0L; } lastTimeStamp = timeStamp; return ((timeStamp - start) << timeStampIdShift
) | (centerId << centerIdShift) | (machineId << machineIdShift) | sequence; }
protected long getNextMillis(long lastTimeStamp) { long timeStamp = System.
currentTimeMillis(); while (timeStamp <= lastTimeStamp) { timeStamp = System.
currentTimeMillis(); } return timeStamp; } public static void main(String[] args
) { System.out.println(new SnowFlakes(0, 0).nextId()); } }