溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

怎么實(shí)現(xiàn)縮小版雪花算法與多線(xiàn)程并發(fā)測(cè)試

發(fā)布時(shí)間:2021-10-23 15:37:33 來(lái)源:億速云 閱讀:539 作者:iii 欄目:編程語(yǔ)言

這篇文章主要講解了“怎么實(shí)現(xiàn)縮小版雪花算法與多線(xiàn)程并發(fā)測(cè)試”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“怎么實(shí)現(xiàn)縮小版雪花算法與多線(xiàn)程并發(fā)測(cè)試”吧!

我們?cè)O(shè)計(jì)數(shù)據(jù)表的時(shí)候,一般都會(huì)有ID字段,ID的生成方法有多種,比如數(shù)據(jù)庫(kù)自增,UUID,雪花算法等。

考慮到以后數(shù)據(jù)的增長(zhǎng),分庫(kù)分表,分布式等要求,我們選擇雪花算法來(lái)生成ID。

開(kāi)發(fā)Web系統(tǒng)需要后端跟前端交互,前端JavaScript支持的最大整型是53位,超過(guò)53位會(huì)丟失精度,原版的雪花算法會(huì)超過(guò)53位,我們使用縮小版的雪花算法,把位數(shù)減小到53位。

原版Snowflake算法的極限是每毫秒的每一個(gè)節(jié)點(diǎn)生成4059個(gè)id值,也就是說(shuō)每毫秒的極限是生成023*4059=4 152 357個(gè)id值 ,縮小后極限是每秒生成15*131071=1 966 065個(gè)分布式id,夠我們?cè)陂_(kāi)發(fā)里面的日常使用了。

package cn.gintone.asso.util;

/**
 * @description:縮小版的雪花算法
 * @author:Elon He
 * @create:2020-10-06
 */
public class SnowflakeMini {
    /**
     * 開(kāi)始時(shí)間截 (1970-01-01)
     */
    private final static long twepoch = 0L;
    /**
     * 機(jī)器id,范圍是1到15
     */
    private final static long workerId =1L;
    /**
     * 機(jī)器id所占的位數(shù),占4位
     */
    private final static long workerIdBits = 4L;
    /**
     * 支持的最大機(jī)器id,結(jié)果是15
     */
    private final static long maxWorkerId = ~(-1L << workerIdBits);
    /**
     * 生成序列占的位數(shù)
     */
    private final static long sequenceBits = 15L;
    /**
     * 機(jī)器ID向左移15位
     */
    private final static long workerIdShift = sequenceBits;
    /**
     * 生成序列的掩碼,這里為最大是32767 (1111111111111=32767)
     */
    private final static long sequenceMask = ~(-1L << sequenceBits);
    /**
     * 時(shí)間截向左移19位(4+15)
     */
    private final static long timestampLeftShift = 19L;
    /**
     * 秒內(nèi)序列(0~32767)
     */
    private static long sequence = 0L;
    /**
     * 上次生成ID的時(shí)間截
     */
    private static long lastTimestamp = -1L;

    /**
     * 獲得下一個(gè)ID (該方法是線(xiàn)程安全的)
     *
     * @return SnowflakeId
     */
    public static synchronized long nextId() {
        //返回以秒為單位的當(dāng)前時(shí)間
        long timestamp = timeGen();
        //如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳,說(shuō)明系統(tǒng)時(shí)鐘回退過(guò)這個(gè)時(shí)候應(yīng)當(dāng)拋出異常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
        //藍(lán)色代碼注釋結(jié)束
        //紅色代碼注釋開(kāi)始
        //如果是同一時(shí)間生成的,則進(jìn)行秒內(nèi)序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            //秒內(nèi)序列溢出
            if (sequence == 0) {
                //阻塞到下一個(gè)秒,獲得新的秒值
                timestamp = tilNextMillis(lastTimestamp);
            }
            //時(shí)間戳改變,秒內(nèi)序列重置
        }
        //紅色代碼注釋結(jié)束
        //綠色代碼注釋開(kāi)始
        else {
            sequence = 0L;
        }
        //綠色代碼注釋結(jié)束
        //上次生成ID的時(shí)間截
        lastTimestamp = timestamp;
        //黃色代碼注釋開(kāi)始
        //移位并通過(guò)或運(yùn)算拼到一起組成53 位的ID
        return ((timestamp - twepoch) << timestampLeftShift)
                | (workerId << workerIdShift)
                | sequence;
        //黃色代碼注釋結(jié)束
    }
    /**
     * 阻塞到下一個(gè)秒,直到獲得新的時(shí)間戳
     *
     * @param lastTimestamp 上次生成ID的時(shí)間截
     * @return 當(dāng)前時(shí)間戳
     */
    protected static long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }
    /**
     * 返回以秒為單位的當(dāng)前時(shí)間
     *
     * @return 當(dāng)前時(shí)間(秒)
     */
    protected static long timeGen() {
        return System.currentTimeMillis()/1000L;
    }

}

創(chuàng)建兩個(gè)線(xiàn)程,同時(shí)測(cè)試ID獲取。
測(cè)試線(xiàn)程類(lèi)A

package cn.gintone.asso;


import cn.gintone.asso.util.SnowflakeMini;

/**
 * @description:線(xiàn)程A
 * @author:Elon He
 * @create:2020-10-06
 */
public class ThreadA extends Thread{

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 10; i++) {
            long id = SnowflakeMini.nextId();
            System.out.println("A:"+id);
        }
    }
}

測(cè)試線(xiàn)程類(lèi)B

package cn.gintone.asso;

import cn.gintone.asso.util.SnowflakeMini;

/**
 * @description:線(xiàn)程B
 * @author:Elon He
 * @create:2020-10-06
 */
public class ThreadB extends  Thread{

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 10; i++) {
            long id = SnowflakeMini.nextId();
            System.out.println("B:"+id);
        }
    }
}

測(cè)試類(lèi)(注釋掉的代碼是修改成靜態(tài)方法前的測(cè)試方法)

package cn.gintone.asso;

/**
 * @description:雪花算法測(cè)試類(lèi)
 * @author:Elon He
 * @create:2020-10-06
 */
public class TestSnowflake {
    public static void main(String[] args) {
        //不同線(xiàn)程使用同一個(gè)對(duì)象,不重復(fù)
//        SnowflakeMini idWorker = new SnowflakeMini(0);
//        ThreadA t1 = new ThreadA(idWorker);
//        ThreadB t2 = new ThreadB(idWorker);
//        t1.start();
//        t2.start();
        //不同線(xiàn)程使用不同對(duì)象,會(huì)重復(fù)
//        SnowflakeMini idWorker1 = new SnowflakeMini(0);
//        SnowflakeMini idWorker2 = new SnowflakeMini(0);
//        ThreadA t1 = new ThreadA(idWorker1);
//        ThreadB t2 = new ThreadB(idWorker2);
//        t1.start();
//        t2.start();

        //nextId修改成靜態(tài)方法后測(cè)試,不重復(fù)
        ThreadA t1 = new ThreadA();
        ThreadB t2 = new ThreadB();
        t1.start();
        t2.start();

    }
}

測(cè)試結(jié)果

怎么實(shí)現(xiàn)縮小版雪花算法與多線(xiàn)程并發(fā)測(cè)試

感謝各位的閱讀,以上就是“怎么實(shí)現(xiàn)縮小版雪花算法與多線(xiàn)程并發(fā)測(cè)試”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)怎么實(shí)現(xiàn)縮小版雪花算法與多線(xiàn)程并發(fā)測(cè)試這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI