您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么實(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è)試”的內(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)注!
免責(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)容。