java唯一字符串ID生成方案詳解
工作中經(jīng)常會(huì)有生成唯一字符串的需求。通常最容易想到的是UUID。UUID的唯一性毋庸置疑,但是32位的長度也容易讓人退避三舍。也曾經(jīng)想過參考《短網(wǎng)址生成方案》來生成一串ID,但是試驗(yàn)了一下發(fā)現(xiàn)唯一性不太好。
最終采用的方案是時(shí)鐘方案,簡單來說就是用當(dāng)前時(shí)間戳做唯一ID。
采用時(shí)間戳做ID,秒或毫秒都容易產(chǎn)生重復(fù),換成納秒在單節(jié)點(diǎn)上就沒問題了。參考百度百科關(guān)于納秒的描述就能清楚為什么納秒級(jí)別的時(shí)間戳不會(huì)產(chǎn)生重復(fù):
光在真空中一納秒僅傳播0.3米。個(gè)人電腦的微處理器執(zhí)行一道指令(如將兩數(shù)相加)約需2至4納秒。
我們生成一條唯一ID所需的CPU指令絕不止一道,因此用納秒作單機(jī)唯一ID是綽綽有余的。在測試中發(fā)現(xiàn),即使是千分之一納秒也足夠我們在PC機(jī)上生成唯一ID了。
至于長度:對原始值做一次Base62處理,長度就能縮減到令人滿意的程度。
不多廢話,直接上代碼:
public static synchronized String gen() {
StringBuilder builder = new StringBuilder(System.nanoTime() / 1000 + "");
if (SEQ.incrementAndGet() % 10 == 0) {
SEQ.incrementAndGet();
}
builder.append(FORMAT.format(SEQ.get()));
if ((MAX_PAD_SIZE - 1) == SEQ.get()) {
SEQ.set(1);
}
long v = Long.parseLong(builder.reverse().toString());
return Base62.encode(v);
}
這里用千分之一納秒做基數(shù)(經(jīng)測試,基數(shù)在10w分之一納秒內(nèi)都是安全的),再加上1~99的順序號(hào)來生成唯一ID。最終可以保證在大于10納秒(近似)的時(shí)間區(qū)間內(nèi)不會(huì)產(chǎn)生重復(fù)值。
為了縮減長度,對字符串做了 Base62處理。在處理前又將納秒數(shù)值做了一次翻轉(zhuǎn)處理。不難想象,如果直接使用原始值來做Base62處理,因?yàn)闀r(shí)鐘的特征,最終生成的值的前幾位都是相同的。
來看一下這個(gè)程序生成的ID:
aSPog4cC
d4t1xZdt
g2tkZVqv
jrinwXx5
m8ZIAKVr
oUB5nzS5
rZa1gPAl
uD12VZ3A
8dnItkTj
八位的長度,唯一且整齊。下面是一個(gè)單元測試:
@Test
public void gen() {
int size = 10240;
Set<String> set = new HashSet<>();
for (int i = 0; i < size; i++) {
String code = ShortCode.gen();
//System.out.println(code);
set.add(code);
}
Assert.assertEquals(size, set.size());
}
這里只對10240的規(guī)模做了測試。因?yàn)槲ㄒ籌D是基于時(shí)鐘生成的,所以測試時(shí)整體規(guī)模的大小不影響ID的唯一性(和短鏈接方案不一樣)。但是太小了也不行——順序號(hào)會(huì)發(fā)揮作用。10240算是一個(gè)中庸的值,足夠暴露問題,也不會(huì)有太多的冗余。
仍然需要強(qiáng)調(diào)一下:這個(gè)方案只能保證在(當(dāng)前)單機(jī)上的唯一性,如果是集群范圍內(nèi)建議采用其他方案,或者加上一兩位機(jī)器ID。
總結(jié)
到此這篇關(guān)于java唯一字符串ID生成方案的文章就介紹到這了,更多相關(guān)java唯一字符串ID生成內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)經(jīng)典游戲2048的示例代碼
2014年Gabriele Cirulli利用周末的時(shí)間寫2048這個(gè)游戲的程序。本文將用java語言實(shí)現(xiàn)這一經(jīng)典游戲,并采用了swing技術(shù)進(jìn)行了界面化處理,需要的可以參考一下2022-02-02
maven項(xiàng)目在實(shí)踐中的構(gòu)建管理之路的方法
這篇文章主要介紹了maven項(xiàng)目在實(shí)踐中的構(gòu)建管理之路的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05
RestTemplate發(fā)送get和post請求,下載文件的實(shí)例
這篇文章主要介紹了RestTemplate發(fā)送get和post請求,下載文件的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
springboot集成redis哨兵集群的實(shí)現(xiàn)示例
本文主要介紹了springboot集成redis哨兵集群的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
springboot 2.x整合mybatis實(shí)現(xiàn)增刪查和批量處理方式
這篇文章主要介紹了springboot 2.x整合mybatis實(shí)現(xiàn)增刪查和批量處理方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09

