最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用雪花id生成算法詳解

 更新時間:2022年12月20日 09:55:27   作者:碼畜c  
SnowFlake算法,是Twitter開源的分布式id生成算法,在2014年開源,開源的版本由scala編寫。其核心思想就是-使用一個64bit的long型的數(shù)字作為全局唯一id

什么是雪花算法

雪花算法的本質(zhì)為生成一個64位長度的具有自增性的分布式全局唯一id。在64bits中,會對不同段的位進行劃分。可分為:

  • 符號段
  • 時間戳段
  • 機器碼段(data center + worker)
  • 自增序列號段

位段詳解

  • 第一位 : 符號位,正數(shù)為0。
  • [2, 42] : 41位時間戳位,表明id的生成時間點(完整時間戳: 起始時間戳 + 41位時間戳)。41位最多能表示的時間為: (2^41-1) / (1000 * 60 * 60 * 24 * 365) 約等為69.73年。
  • [43, 47] : 5位data center id。data center id + worker id 共10位,最多能表示1024個機器。不同機器保證機器碼段的位值不同即可。
  • [48, 52] : 5位worker id。data center id + worker id 共10位,最多能表示1024個機器。不同機器保證機器碼段的位值不同即可。
  • [53, 64] : 12位自增序列號,用于區(qū)分同一毫秒內(nèi)生成的id。序列號范圍: [0, 2^12-1],最多有2^12個,即4096個。

優(yōu)點

  • 算法簡單,基于內(nèi)存,生成效率高
  • 支持分布式環(huán)境下的多節(jié)點服務(wù)(機器碼段),秒內(nèi)可生成百萬個唯一id
  • 基于時間戳 與 同時間戳下自增序列號,生成的id具有自增性
  • 具有業(yè)務(wù)定制性,根據(jù)業(yè)務(wù)的不同可以對不同段的位數(shù)進行變更。比如業(yè)務(wù)持續(xù)時長不會那么久,就可以將時間戳段減少位數(shù),補充給自增序列段,使每一毫秒能生成更多的id。

問題

依賴服務(wù)器時間。若服務(wù)器時鐘回撥,可能會導(dǎo)致生成的id重復(fù)。可在代碼中新增lastTimeMillis字段,在獲取nextId時根據(jù)系統(tǒng)當前時間進行判斷解決。

但若不進行持久化處理,服務(wù)重啟后發(fā)生時鐘回撥依舊會出現(xiàn)重復(fù)問題。

實際應(yīng)用

  • mybatis plus:使用雪花算法生成id:@TableId(value = “id”, type = IdType.ID_WORKER)。id字段若不指定類型,默認使用雪花算法生成id
  • Hutool工具包:IdUtil.createSnowflake(workerId, datacenterId);

具體實現(xiàn)

/**
 * Created by QQ.Cong on 2022-07-22 / 9:48
 *
 * @author: CongQingquan
 * @Description: Snowflake util
 */
public class SnowflakeUtils {
    // ============================== Basic field ==============================//
    // Datacenter id
    private long datacenterId;
    // Worker id
    private long workerId;
    // Increment sequence
    private long sequence;
    // ============================== Bits ==============================//
    // Bits of datacenter id
    private long datacenterIdBits;
    // Bits of worker id
    private long workerIdBits;
    // Bits of sequence
    private long sequenceBits;
    // ============================== Largest ==============================//
    // Largest datacenter id
    private long largestDatacenterId;
    // Largest worker id
    private long largestWorkerId;
    // Largest sequence
    private long largestSequence;
    // ============================== Shift ==============================//
    // Left shift num of worker id
    private long workerIdShift;
    // Left shift num of datacenter id
    private long datacenterIdShift;
    // Left shift num of timestamp
    private long timestampShift;
    // ============================== Other ==============================//
    // Epoch
    private long epoch;
    // The timestamp that last get snowflake id
    private long lastTimestamp;
    // ============================== End ==============================//
    public SnowflakeUtils(long dataCenterId, long workerId) {
        // Default epoch: 2022-07-22 00:00:00
        this(1658419200000L, -1L, dataCenterId, workerId, 5L, 5L, 5L);
    }
    public SnowflakeUtils(long epoch, long lastTimestamp, long datacenterId, long workerId,
        long datacenterIdBits, long workerIdBits, long sequenceBits) {
        this.epoch = epoch;
        this.lastTimestamp = lastTimestamp;
        this.datacenterId = datacenterId;
        this.workerId = workerId;
        this.sequence = 0L;
        this.datacenterIdBits = datacenterIdBits;
        this.workerIdBits = workerIdBits;
        this.sequenceBits = sequenceBits;
        this.largestDatacenterId = ~(-1L << datacenterIdBits);
        this.largestWorkerId = ~(-1L << workerIdBits);
        this.largestSequence = ~(-1L << sequenceBits);
        if (datacenterId > largestDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(
                String.format("The datacenter id param can't be greater than %s or less than 0",
                    largestDatacenterId));
        }
        if (workerId > largestWorkerId || workerId < 0) {
            throw new IllegalArgumentException(
                String.format("The worker id param can't be greater than %s or less than 0",
                    largestWorkerId));
        }
        this.workerIdShift = sequenceBits;
        this.datacenterIdShift = workerIdShift + workerIdBits;
        this.timestampShift = datacenterIdShift + datacenterIdBits;
    }
    /**
     * Get snowflake id
     * @return
     */
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();
        // 若時鐘回退
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                "System clock moved backward, cannot to generate snowflake id");
        }
        // 若當前毫秒內(nèi)多次生成雪花id
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & largestSequence;
            // 序列溢出
            if (sequence == 0) {
                timestamp = waitUntilNextMilli(timestamp);
            }
        }
        // 若當前毫秒內(nèi)首次生成雪花id
        else {
            sequence = 0L;
        }
        // 更新獲取雪花id的時間戳
        lastTimestamp = timestamp;
        // 生成雪花id (通過位或運算符進行拼接)
        return ((timestamp - epoch) << timestampShift) // 時間戳段
            | (datacenterId << datacenterIdShift) // 機器碼段
            | (workerId << workerIdShift) // 機器碼段
            | sequence; // 自增序列段
    }
    /**
     * Wait until next millisecond
     * @param lastTimestamp
     * @return
     */
    private long waitUntilNextMilli(long lastTimestamp) {
        long currentTimeMillis;
        do {
            currentTimeMillis = System.currentTimeMillis();
        }
        while (currentTimeMillis <= lastTimestamp);
        return currentTimeMillis;
    }
    /**
     * Get util instance
     * @param dataCenterId
     * @param workerId
     * @return
     */
    public static SnowflakeUtils getInstance(long dataCenterId, long workerId) {
        return new SnowflakeUtils(dataCenterId, workerId);
    }
}

到此這篇關(guān)于Java使用雪花id生成算法詳解的文章就介紹到這了,更多相關(guān)Java雪花id生成算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot+MyBatis-Plus+Velocity實現(xiàn)代碼自動生成

    SpringBoot+MyBatis-Plus+Velocity實現(xiàn)代碼自動生成

    本文主要介紹了使用SpringBoot、MyBatis-Plus和Velocity模板引擎實現(xiàn)代碼自動生成器,該生成器能夠根據(jù)數(shù)據(jù)庫表結(jié)構(gòu)自動生成增刪改查操作的代碼,感興趣的可以了解一下
    2025-03-03
  • Java方法的可變參數(shù)類型實例分析

    Java方法的可變參數(shù)類型實例分析

    這篇文章主要介紹了Java方法的可變參數(shù)類型,通過實例對Java中的可變參數(shù)類型進行了較為深入的分析,需要的朋友可以參考下
    2014-09-09
  • java jdbc連接和使用詳細介紹

    java jdbc連接和使用詳細介紹

    這篇文章主要介紹了 java jdbc連接和使用詳細介紹的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • java通過信號量實現(xiàn)限流的示例

    java通過信號量實現(xiàn)限流的示例

    本文主要介紹了java通過信號量實現(xiàn)限流的示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java設(shè)計模式之java責(zé)任鏈模式詳解

    Java設(shè)計模式之java責(zé)任鏈模式詳解

    這篇文章主要介紹了JAVA 責(zé)任鏈模式的的相關(guān)資料,文中講解非常細致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2021-09-09
  • Java中字符序列的替換與分解的幾種實現(xiàn)方法

    Java中字符序列的替換與分解的幾種實現(xiàn)方法

    本文主要介紹了Java中字符序列的替換與分解的幾種實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 簡析Java中的util.concurrent.Future接口

    簡析Java中的util.concurrent.Future接口

    這篇文章主要介紹了簡析Java中的util.concurrent.Future接口,作者把future歸結(jié)為在未來得到目標對象的占位符,需要的朋友可以參考下
    2015-07-07
  • Java技巧函數(shù)方法實現(xiàn)二維數(shù)組遍歷

    Java技巧函數(shù)方法實現(xiàn)二維數(shù)組遍歷

    這篇文章主要介紹了Java技巧函數(shù)方法實現(xiàn)二維數(shù)組遍歷,二維數(shù)組遍歷,每個元素判斷下是否為偶數(shù),相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-08-08
  • Java中的信號量Semaphore詳細解讀

    Java中的信號量Semaphore詳細解讀

    這篇文章主要介紹了Java中的信號量Semaphore詳細解讀,Java信號量機制可以用來保證線程互斥,創(chuàng)建Semaphore對象傳入一個整形參數(shù),類似于公共資源,需要的朋友可以參考下
    2023-11-11
  • MyBatis驗證多級緩存及 Cache Aside 模式的應(yīng)用小結(jié)

    MyBatis驗證多級緩存及 Cache Aside 模式的應(yīng)用小結(jié)

    本文介紹了MyBatis的多級緩存機制,包括本地緩存和全局緩存,并通過Spock測試框架驗證了多級緩存的實現(xiàn),本文結(jié)合實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-12-12

最新評論

云浮市| 江山市| 永宁县| 汶上县| 樟树市| 阿巴嘎旗| 左权县| 永宁县| 南和县| 泾阳县| 彭山县| 东宁县| 武冈市| 基隆市| 福建省| 中江县| 安陆市| 惠州市| 固始县| 道孚县| 墨竹工卡县| 子洲县| 太仆寺旗| 诸暨市| 叶城县| 额济纳旗| 乌海市| 宿松县| 陇川县| 永新县| 闽侯县| 兴仁县| 宝兴县| 固阳县| 华宁县| 华容县| 平和县| 集贤县| 夏邑县| 万山特区| 海阳市|