女艾滋病的早期症状,成飞中学学生,齐齐哈尔论坛
要生成uuid,大多会直接使用下面这句:
uuid.randomuuid().tostring().replace("-", "");
在多数情况,这样的处理是没问题的,毕竟是jdk标准接口。但是在某些情况下,会出现重复。搜素 uuid 重复,就会发现有人踩到了雷
先看uuid各版本的实现原理:universally unique identifier
再看jdk的实现(只实现了uuid的1,3,4版本):java.util.uuid
会发现在分布式场景下jdk自带的这个工具类并不好用。原因:
通过这种消耗大量性能来获取uuid,当然可行,但在高并发的场景下你真的会去考虑吗?
分布式?多台web容器(我们可以称之为实例)在同1个机器(mac地址相同)下?不依赖第3方工具?最好在jvm解决?
确保每台实例具有唯一的名字(我们可以称之为实例名)
确保某台实例生成的uuid不会重复: 当前系统时间 + 递增的数值(避免高并发的影响)
因此,算法如下:
uuid = 实例名 + 当前系统时间毫秒数 + 递增的int数
对每台web容器的java_options配置不一样的实例名
以tomcat(8.0.53)为例,在startup.bat里配置:
rem to set java_opts set "java_opts=%java_opts% -dinstance.name=cico-mba"
这样,上文的instance.name,就变成了jvm里的1个参数了
代码实现
package java.main; import java.util.concurrent.atomic.atomicinteger; public class uuidutil { /* 从当前web容器的java_options中,获取jvm的配置:当前实例名 */ private static final string instance_name = system.getproperty("instance.name"); /* 实例名脱敏后的值 */ private static string instance_name_by_num = null; /* 计数器。atomicinteger是java.util.concurrent下的类,jdk的算法工程师会避免并发问题 */ private static atomicinteger cnt = new atomicinteger(0); /** * 初始化instance_name_by_num。需考虑并发 */ private synchronized static void initinstancenamebynum() { if (null != instance_name_by_num) { return; } char[] chars = instance_name.tochararray(); stringbuilder sb = new stringbuilder(); for (char c : chars) { sb.append((int) c); } instance_name_by_num = sb.tostring(); } /** * 生成分布式的uuid * * @return */ public static string getconcurrentuuid() { if (null == instance_name) { return "the jvm option is null, named 'instance.name'"; } if (null == instance_name_by_num) { initinstancenamebynum(); } stringbuilder uuid = new stringbuilder(); uuid.append(instance_name_by_num); uuid.append(system.currenttimemillis()); uuid.append(cnt.incrementandget()); return uuid.tostring(); } }
通过上文的方法可在jvm内快速生成支持分布式的uuid。这个uuid的长度,由下面3部分组成:
如果这个uuid需要持久化,持久化的字段可定义成varchar2(255),其中实例名的字符长度最大可以是115 = ( 255 - 13 - 11 ) / 2
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
如何在java 8 stream表达式实现if/else逻辑
Java中有界队列的饱和策略(reject policy)原理解析
网友评论