java唯一字符串ID生成方案详解

网友投稿 510 2022-11-19


java唯一字符串ID生成方案详解

工作中经常会有生成唯一字符串的需求。通常最容易想到的是UUID。UUID的唯一性毋庸置疑,但是32位的长度也容易让人退避三舍。也曾经想过参考《短网址生成方案》来生成一串ID,但是试验了一下发现唯一性不太好。

最终采用的方案是时钟方案,简单来说就是用当前时间戳做唯一ID。

采用时间戳做ID,秒或毫秒都容易产生重复,换成纳秒在单节点上就没问题了。参考百度百科关于纳秒的描述就能清楚为什么纳秒级别的时间戳不会产生重复:

光在真空中一纳秒仅传播0.3米。个人电脑的微处理器执行一道指令(如将两数相加)约需2至4纳秒。

我们生成一条唯一ID所需的CPU指令绝不止一道,因此用纳秒作单机唯一ID是绰绰有余的。在测试中发现,即使是千分之一纳秒也足够我们在PC机上生成唯一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)http://;

}

long v = Long.parseLong(builder.reverse().toString());

return Base62.encode(v);

}

这里用千分之一纳秒做基数(经测试,基数在10w分之一纳秒内都是安全的),再加上1~99的顺序号来生成唯一ID。最终可以保证在大于10纳秒(近似)的时间区间内不会产生重复值。

为了缩减长度,对字符串做了 Base62处理。在处理前又将纳秒数值做了一次翻转处理。不难想象,如果直接使用原始值来做Base62处理,因为时钟的特征,最终生成的值的前几位都是相同的。

来看一下这个程序生成的ID:

aSPog4cC

d4t1xZdt

g2tkZVqv

jrinwXx5

m8ZIAKVr

oUB5nzS5

rZa1gPAl

uD12VZ3A

8dnItkTj

八位的长度,唯一且整齐。下面是一个单元测试:

@Test

public void gen() {

int size = 10240;

Set 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的规模做了测试。因为唯一ID是基于时钟生成的,所以测试时整体规模的大小不影响ID的唯一性(和短链接方案不一样)。但是太小了也不行——顺序号会发挥作用。10240算是一个中庸的值,足够暴露问题,也不会有太多的冗余。

仍然需要强调一下:这个方案只能保证在(当前)单机上的唯一性,如果是集群范围内建议采用其他方案,或者加上一两位机器ID。

总结


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:短网址的原理与生成方法(Java实现)
下一篇:mybatis中实现让返回值与bean中字段相匹配
相关文章

 发表评论

暂时没有评论,来抢沙发吧~