SnowFlake演算法產生id的結果是一個64bit大小的整數,它的結構如下圖:
##分為四段: 第一段: 1位元為未使用,永遠固定為0。 (因為二進位中最高位是符號位,1表示負數,0表示正數。產生的id一般都是用正整數,所以最高位固定為0 )第二段: 41位元為毫秒時間(41位元的長度可以使用69年)第三段: 10位元為workerId(10位元的長度最多支援部署1024個節點) (這裡的10位又分為兩部分,第一部分5位表示資料中心ID(0-31)第二部分5位表示機器ID(0-31))第四段: 12位為毫秒內的計數(12位元的計數順序號支援每個節點每毫秒產生4096個ID序號)程式碼實作:import java.util.HashSet; import java.util.concurrent.atomic.AtomicLong; public class SnowFlake { //时间 41位 private static long lastTime = System.currentTimeMillis(); //数据中心ID 5位(默认0-31) private long datacenterId = 0; private long datacenterIdShift = 5; //机房机器ID 5位(默认0-31) private long workerId = 0; private long workerIdShift = 5; //随机数 12位(默认0~4095) private AtomicLong random = new AtomicLong(); private long randomShift = 12; //随机数的最大值 private long maxRandom = (long) Math.pow(2, randomShift); public SnowFlake() { } public SnowFlake(long workerIdShift, long datacenterIdShift){ if (workerIdShift < 0 || datacenterIdShift < 0 || workerIdShift + datacenterIdShift > 22) { throw new IllegalArgumentException("参数不匹配"); } this.workerIdShift = workerIdShift; this.datacenterIdShift = datacenterIdShift; this.randomShift = 22 - datacenterIdShift - workerIdShift; this.maxRandom = (long) Math.pow(2, randomShift); } //获取雪花的ID private long getId() { return lastTime << (workerIdShift + datacenterIdShift + randomShift) | workerId << (datacenterIdShift + randomShift) | datacenterId << randomShift | random.get(); } //生成一个新的ID public synchronized long nextId() { long now = System.currentTimeMillis(); //如果当前时间和上一次时间不在同一毫秒内,直接返回 if (now > lastTime) { lastTime = now; random.set(0); return getId(); } //将最后的随机数,进行+1操作 if (random.incrementAndGet() < maxRandom) { return getId(); } //自选等待下一毫秒 while (now <= lastTime) { now = System.currentTimeMillis(); } lastTime = now; random.set(0); return getId(); } //测试 public static void main(String[] args) { SnowFlake snowFlake = new SnowFlake(); HashSet<Long> set = new HashSet<>(); for (int i = 0; i < 10000; i++) { set.add(snowFlake.nextId()); } System.out.println(set.size()); } }程式碼中取得id的方法利用位元運算實現
1 | 41 0|0001100 10100010 10111110 10001001 01011100 00|00000|0 0000|0000 00000000/ /41位元的時間 0|0000000 00000000 00000000 00000000 00000000 00|10001|0 0000|00000000 00|10000 00000 00000000 00000000 00000000 00|00000|1 1001|0000 00000000 //5為的機器IDor 0|0000000 00000000 00000000 00000000 0000000 00000000000 sequence----------------------------------------------- ------------------------------------------- 0 |0001100 10100010 10111110 10001001 01011100 00|10001|1 1001|0000 00000000 //結果:9104995718479000 00000000增整個分佈式系統內不會產生重複id(因為有datacenterId和workerId來做區分) SnowFlake不足:由於SnowFlake強依賴時間戳,所以時間的變動會造成SnowFlake的演算法產生錯誤。
以上是Java怎麼透過手寫分散式雪花SnowFlake產生ID的詳細內容。更多資訊請關注PHP中文網其他相關文章!