算法:第一章:SnowFlake算法(分布式系統(tǒng)中生成唯一的ID的算法)SnowFlake每秒能夠產(chǎn)生26萬ID左右

不廢話了,直接上代碼:

    package cn.springboot.config.db.pk.local.impl;
     
    /**
     * The class Snowflake id generator. Created by paascloud.net@gmail.com
     * Twitter雪花ID算法
     * 概述
     * - SnowFlake算法是Twitter設(shè)計(jì)的一個可以在分布式系統(tǒng)中生成唯一的ID的算法,它可以滿足Twitter每秒上萬條消息ID分配的請求,這些消息ID是唯一的且有大致的遞增順序
     *
     * 原理
     * - SnowFlake算法產(chǎn)生的ID是一個64位的整型,結(jié)構(gòu)如下(每一部分用“-”符號分隔):
     *    0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
     * - 1位標(biāo)識部分,在java中由于long的最高位是符號位,正數(shù)是0,負(fù)數(shù)是1,一般生成的ID為正數(shù),所以為0
     * - 41位時間戳部分,這個是毫秒級的時間,一般實(shí)現(xiàn)上不會存儲當(dāng)前的時間戳,而是時間戳的差值(當(dāng)前時間-固定的開始時間),這樣可以使產(chǎn)生的ID從更小值開始;41位的時間戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
     * - 10位節(jié)點(diǎn)部分,Twitter實(shí)現(xiàn)中使用前5位作為數(shù)據(jù)中心標(biāo)識,后5位作為機(jī)器標(biāo)識,可以部署1024個節(jié)點(diǎn)
     * - 12位序列號部分,12位的計(jì)數(shù)順序號支持每個節(jié)點(diǎn)每毫秒(同一機(jī)器,同一時間戳)產(chǎn)生4096個ID序號,加起來剛好64位,為一個Long型
     *  
     * 優(yōu)點(diǎn)
     * - SnowFlake的優(yōu)點(diǎn)是,整體上按照時間自增排序,并且整個分布式系統(tǒng)內(nèi)不會產(chǎn)生ID碰撞(由數(shù)據(jù)中心ID和機(jī)器ID作區(qū)分),并且效率較高,經(jīng)測試,SnowFlake每秒能夠產(chǎn)生26萬ID左右
     *
     * 使用
     * - SnowFlake算法生成的ID大致上是按照時間遞增的,用在分布式系統(tǒng)中時,需要注意數(shù)據(jù)中心標(biāo)識和機(jī)器標(biāo)識必須唯一,這樣就能保證每個節(jié)點(diǎn)生成的ID都是唯一的。
     *   或許我們不一定都需要像上面那樣使用5位作為數(shù)據(jù)中心標(biāo)識,5位作為機(jī)器標(biāo)識,可以根據(jù)我們業(yè)務(wù)的需要,靈活分配節(jié)點(diǎn)部分,如:若不需要數(shù)據(jù)中心,完全可以使用全部10位作為機(jī)器標(biāo)識;若數(shù)據(jù)中心不多,也可以只使用3位作為數(shù)據(jù)中心,7位作為機(jī)器標(biāo)識
     */
    public class SnowflakeIdGenerator {
        /**
         * 每一部分占用的位數(shù)
         */
        private final static long DATA_CENTER_ID_BITS = 5L; // 數(shù)據(jù)中心標(biāo)識在ID中占用的位數(shù)
        private final static long MACHINE_ID_BITS = 5L; // 機(jī)器標(biāo)識在ID中占用的位數(shù)
        private final static long SEQUENCE_BITS = 12L; // 序列號在ID中占用的位數(shù)
     
        /**
         * 每一部分的最大值
         */
        private final static long MAX_DATA_CENTER_ID = -1L ^ (-1L << DATA_CENTER_ID_BITS); // 支持的最大數(shù)據(jù)中心標(biāo)識ID為31
        private final static long MAX_MACHINE_ID = -1L ^ (-1L << MACHINE_ID_BITS); // 支持的最大機(jī)器標(biāo)識ID為31(這個移位算法可以很快的計(jì)算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù))
        private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BITS); // 支持的最大序列(掩碼), 這里為4095 (0b111111111111=0xfff=4095)
     
        /**
         * 每一部分向左的位移
         */
        private final static long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS; // 數(shù)據(jù)中心標(biāo)識ID向左移17位(12+5)
        private final static long MACHINE_ID_SHIFT = SEQUENCE_BITS; // 機(jī)器標(biāo)識ID向左移12位
        private final static long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATA_CENTER_ID_BITS; // 時間戳向左移22位(5+5+12)
     
        /**
         * 批量獲取的最大數(shù)目(10萬)
         */
        private final static int MAX_BATCH_COUNT = 100_000;
     
        /**
         * 變量部分
         */
        private long dataCenterId; // 數(shù)據(jù)中心標(biāo)識ID(0~31)
        private long machineId; // 機(jī)器標(biāo)識ID(0~31)
        private long sequence = 0L; // 毫秒內(nèi)序列(0~4095)
        private long startTimestamp = -1L; // 開始時間戳
        private long lastTimestamp = -1L; // 上次生成ID的時間戳
     
        /**
         * 構(gòu)造方法
         * @param startTimestamp 開始時間戳,不可大于當(dāng)前時間
         * @param dataCenterId 數(shù)據(jù)中心標(biāo)識ID(0~31)
         * @param machineId 機(jī)器標(biāo)識ID(0~31)
         */
        public SnowflakeIdGenerator(long startTimestamp, long dataCenterId, long machineId) {
            long currentTimestamp = getCurrentTimestamp();
            if (startTimestamp > currentTimestamp) {
                throw new RuntimeException(String.format("Start timestamp can't be greater than %d", currentTimestamp));
            }
     
            if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
                throw new RuntimeException(String.format("Data center id can't be greater than %d or less than 0", MAX_DATA_CENTER_ID));
            }
     
            if (machineId > MAX_MACHINE_ID || machineId < 0) {
                throw new RuntimeException(String.format("Machine id can't be greater than %d or less than 0", MAX_MACHINE_ID));
            }
     
            // 當(dāng)初始時間跟當(dāng)前時間相等,減1毫秒,否則會導(dǎo)致溢出
            this.startTimestamp = (startTimestamp == currentTimestamp ? startTimestamp - 1 : startTimestamp);
            this.dataCenterId = dataCenterId;
            this.machineId = machineId;
        }
     
        /**
         * 批量獲取下一組ID
         * @param count 批量條數(shù)
         * @return
         */
        public String[] nextIds(int count) {
            if (count <= 0 || count > MAX_BATCH_COUNT) {
                throw new RuntimeException(String.format("Count can't be greater than %d or less than 0", MAX_BATCH_COUNT));
            }
     
            String[] ids = new String[count];
            for (int i = 0; i < count; i++) {
                ids[i] = nextId();
            }
     
            return ids;
        }
     
        /**
         * 獲得下一個ID (該方法是線程安全的)
         * @return
         */
        public synchronized String nextId() {
            long currentTimestamp = getCurrentTimestamp();
     
            // 如果當(dāng)前時間小于上一次ID生成的時間戳, 說明系統(tǒng)時鐘回退過這個時候應(yīng)當(dāng)拋出異常
            if (currentTimestamp < lastTimestamp) {
                throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - currentTimestamp));
            }
     
            // 如果是同一時間生成的, 則進(jìn)行毫秒內(nèi)序列自增
            if (lastTimestamp == currentTimestamp) {
                // 相同毫秒內(nèi),序列號自增
                sequence = (sequence + 1) & MAX_SEQUENCE;
                // 同一毫秒的序列數(shù)已經(jīng)達(dá)到最大,則毫秒內(nèi)序列溢出
                if (sequence == 0) {
                    // 阻塞到下一個毫秒,獲得新的時間戳
                    currentTimestamp = getNextTimestamp(lastTimestamp);
                }
            } else {
                // 不同毫秒內(nèi),序列號置為0
                sequence = 0L;
            }
     
            // 上次生成ID的時間戳
            lastTimestamp = currentTimestamp;
     
            // 移位并通過或運(yùn)算拼到一起組成64位的ID
            long id = ((currentTimestamp - startTimestamp) << TIMESTAMP_SHIFT) // 時間戳部分
                | (dataCenterId << DATA_CENTER_ID_SHIFT) // 數(shù)據(jù)中心標(biāo)識ID部分
                | (machineId << MACHINE_ID_SHIFT) // 機(jī)器標(biāo)識ID部分
                | sequence; // 序列號部分
     
            return String.valueOf(id);
        }
     
        /**
         * 阻塞到下一個毫秒, 直到獲得新的時間戳
         * @param lastTimestamp 上次生成ID的時間戳
         * @return 當(dāng)前時間戳
         */
        private long getNextTimestamp(long lastTimestamp) {
            long currentTimestamp = getCurrentTimestamp();
            while (currentTimestamp <= lastTimestamp) {
                currentTimestamp = getCurrentTimestamp();
            }
     
            return currentTimestamp;
        }
     
        /**
         * 返回以毫秒為單位的當(dāng)前時間
         * @return 當(dāng)前時間(毫秒)
         */
        private long getCurrentTimestamp() {
            return System.currentTimeMillis();
        }
     
        public static void main(String[] args) {
            SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1483200000000L, 2, 3);
     
            for (int i = 0; i < 1000; i++) {
                System.out.println(generator.nextId());
            }
        }
    }