日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

雪花算法之唯一ID生成器理解

發布時間:2024/4/18 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 雪花算法之唯一ID生成器理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

雪花算法基本情況

  • 雪花算法是一個分布式的唯一ID生成器。
  • 它應該具有高并發,以及高性能優點。
  • 基于時間戳,ID具有有序性,同時分布式下機器間時間差異過大(類似同一臺機器時間回撥,一定會重復),會導致重復ID。
  • 基于機器碼和操作中心id,ID具有不可重復性。
  • 它的ID是8字節64bit的一個Long長整型數據。

ID基本組成

ID基本組成:
不用: 1bit,因為最高位是符號位,0表示正,1表示負,所以這里固定為0
時間戳: 41bit,服務上線的時間毫秒級的時間戳(為當前時間-服務第一次上線時間),這里為(2^41-1)/1000/60/60/24/365 = 49.7年
工作機器id: 10bit,表示工作機器id,用于處理分布式部署id不重復問題,可支持2^10 = 1024個節點
序列號: 12bit,用于離散同一機器同一毫秒級別生成多條Id時,可允許同一毫秒生成2^12 = 4096個Id,則一秒就可生成4096*1000 = 400w個Id


這樣看,在分布式時,通過時間戳+工作機器ID+散列序列號,幾乎不會重復,當然你必須保證工作機器ID的準確配置。

源碼簡易分析以及注意事項

我們以mybatisplus實現的雪花算法為例:

  • IdWorker類:
    注意:DefaultIdentifierGenerator()這個必須是單例模式的,否者在多線程高并發下,會有重復ID,而且很多。詳見IDENTIFIER_GENERATOR.nextId(entity)這個方法實現
package com.baomidou.mybatisplus.core.toolkit;import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom;public class IdWorker {/**單例模式,否者會多個重復Id,詳見IDENTIFIER_GENERATOR.nextId(entity).longValue()*/private static IdentifierGenerator IDENTIFIER_GENERATOR = new DefaultIdentifierGenerator();public static final DateTimeFormatter MILLISECOND = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");public IdWorker() {}/**獲取Id*/public static long getId() {return getId(new Object());}/**獲取Id,最終都會走這一步*/public static long getId(Object entity) {return IDENTIFIER_GENERATOR.nextId(entity).longValue();}/**機器碼和數據中心的ID,參數不能重復*/public static void initSequence(long workerId, long dataCenterId) {IDENTIFIER_GENERATOR = new DefaultIdentifierGenerator(workerId, dataCenterId);} }
  • IDENTIFIER_GENERATOR.nextId(entity).longValue() 方法
    nextId是一個線程安全的方法,這也是多線程唯一Id生成的必要之一。
    synchronized并不會直接轉成重量級鎖,因為java在1.6已經優化,因此在資源上沒有過分占用,是從偏向鎖,輕量級鎖,再到重量級鎖的過程。
public synchronized long nextId() {/** long timestamp = this.timeGen();這步代碼一定要注意當你DefaultIdentifierGenerator是多例時,這里獲取的timestamp不具有真正的唯一性,因為多個實例一起在工作,所以寫工具類時不要寫成多例 */long timestamp = this.timeGen();// 這里是時間異常,針對分布式下,不同機器時間的差異過大if (timestamp < this.lastTimestamp) {long offset = this.lastTimestamp - timestamp;if (offset > 5L) {throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));}try {this.wait(offset << 1);timestamp = this.timeGen();if (timestamp < this.lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));}} catch (Exception var6) {throw new RuntimeException(var6);}}if (this.lastTimestamp == timestamp) {this.sequence = this.sequence + 1L & 4095L;if (this.sequence == 0L) {// 散列序列號沒了,必須轉到下一毫秒,采用阻塞timestamp = this.tilNextMillis(this.lastTimestamp);}} else {// 散列序列號this.sequence = ThreadLocalRandom.current().nextLong(1L, 3L);}this.lastTimestamp = timestamp;// 或運算連接運算后的時間戳,數據中心,工作中心,序列號的bit位,會被自動返回為一個長整型的數據。return timestamp - 1288834974657L << 22 | this.datacenterId << 17 | this.workerId << 12 | this.sequence;}

雪花算法很好用,讓我了解了更多的東西,學習了。

總結

以上是生活随笔為你收集整理的雪花算法之唯一ID生成器理解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。