在java中生成唯一的值会导致重复
我有一个在java中生成唯一ID的逻辑,如下所示在java中生成唯一的值会导致重复,java,Java,我有一个在java中生成唯一ID的逻辑,如下所示 private static String generateUniqueNum() { final int LENGTH = 20; final long uniqueNumber = abs(Long.valueOf(UUID.randomUUID().hashCode())) + System.currentTimeMillis() + abs(random.nextLong());
private static String generateUniqueNum()
{
final int LENGTH = 20;
final long uniqueNumber = abs(Long.valueOf(UUID.randomUUID().hashCode())) + System.currentTimeMillis() + abs(random.nextLong());
String value = Long.toString(uniqueNumber).replaceAll("-", "");
final int endIndex = value.length() <= LENGTH ? value.length() : LENGTH;
return String.format("MN%s", value.substring(0, endIndex));
}
private static Long abs(Long number){
if(null == number || 0 < number){
return 0L;
}
return Math.abs(number);
}
private静态字符串generateUniqueNum()
{
最终整数长度=20;
final long uniqueNumber=abs(long.valueOf(UUID.randomuid().hashCode())+System.currentTimeMillis()+abs(random.nextLong());
字符串值=Long.toString(uniqueNumber.replaceAll(“-”,”);
final int endIndex=value.length()UUID是唯一的,但使用128位(两个长)
最好使用数据库键,例如字符串表示法。对于不太安全的长
:
return uuid.getLeastSignificantBits() ^ uuid.getMostSignificantBits();
冲突源于散列码是int(32位,四分之一),与其他属性组合不一定会使数字更随机;甚至更少。UUID是唯一的,但使用128位(两个长)
最好使用数据库键,例如字符串表示法。对于不太安全的长
:
return uuid.getLeastSignificantBits() ^ uuid.getMostSignificantBits();
您的冲突源于哈希代码是整数(32位,四分之一),与其他属性相结合不一定会使数字更随机;甚至更不随机。您当前的方法几乎没有问题:
java.util.Random
不是线程安全的。如果在不同线程上对同一Random
对象有3000个并发请求,则可能会出现奇怪的行为。请改为尝试ThreadLocalRandom
如果3000个并发请求同时发生,则生成的System.currentTimeMillis()
值将非常接近
如果需要唯一标识符,请不要使问题过于复杂:
使用UUID v4(UUID.randomUUID()
),或者如果您需要更强大的保证UUID v1。UUID中有足够的随机位来保证这一点
如果您需要更简洁的东西,请维护一个共享计数器,例如数据库序列。每次需要新的唯一编号时,只需增加一个即可
您当前的方法几乎没有问题:
java.util.Random
不是线程安全的。如果在不同线程上对同一Random
对象有3000个并发请求,则可能会出现奇怪的行为。请改为尝试ThreadLocalRandom
如果3000个并发请求同时发生,则生成的System.currentTimeMillis()
值将非常接近
如果需要唯一标识符,请不要使问题过于复杂:
使用UUID v4(UUID.randomUUID()
),或者如果您需要更强大的保证UUID v1。UUID中有足够的随机位来保证这一点
如果您需要更简洁的东西,请维护一个共享计数器,例如数据库序列。每次需要新的唯一编号时,只需增加一个即可
问:为什么您的方案具有显著的非唯一性
有一只臭虫在吼叫
private static Long abs(Long number){
if(null == number || 0 < number){
return 0L;
}
return Math.abs(number);
}
但是由于您的错误,第一个术语为零的概率为50%,最后一个术语为零的概率为50%
因此有25%的概率,您的“随机”数将是以毫秒为单位的当前时间!现在假设您在毫秒内调用generateUniqueNum()
两次
哎呀
请注意,如果没有此错误,您的代码生成的任何一对数字仍然有1/264的机会相等。如果您将此与“生日悖论”分析相结合,则任何冲突的概率都会变得显著。Q:为什么您的方案会给出显著的非唯一性
有一只臭虫在吼叫
private static Long abs(Long number){
if(null == number || 0 < number){
return 0L;
}
return Math.abs(number);
}
但是由于您的错误,第一个术语为零的概率为50%,最后一个术语为零的概率为50%
因此有25%的概率,您的“随机”数将是以毫秒为单位的当前时间!现在假设您在毫秒内调用generateUniqueNum()
两次
哎呀
请注意,如果没有这个bug,您的代码仍有可能在264分之一的情况下,生成的任何一对数字都是相等的通过分析,任何冲突的概率都变得非常重要。不要向UUID添加任何内容:它本身保证是唯一的。删除System.currentTimeMillis()
。不要在UUID上使用hashCode
:使用toString
:UUID.randomUUID().toString()
足够了。另外,您的abs
方法有缺陷:如果数字>0,则返回0,否则返回Math.abs???您确定此算法吗?您仍在UUID上使用hashcode:这不起作用…使用:UUID.randomUUID().toString()
通过执行+abs(random.nextLong())
在此之前,您基本上可以扔掉所有东西;您的“唯一”数字将只是一个(或多或少)随机长数。不要向UUID添加任何东西:它本身保证是唯一的。删除System.currentTimeMillis()
。不要在UUID上使用hashCode
:使用toString
:UUID.randomUUID().toString()
就足够了。另外,您的abs
方法有缺陷:如果数字>0,则返回0,否则返回Math.abs???您确定此算法吗?您仍然在UUID上使用hashcode:这不起作用…使用:UUID.randomUUID().toString()
通过执行+abs(random.nextLong())
在此之前,您基本上可以扔掉所有东西;您的“唯一”数将只是一个(或多或少)随机长数……最重要的是,不能保证hashCode均匀分布……public int hashCode(){return 42;}
是一个完全有效的实现……最重要的是,不能保证hashCode是均匀分布的……public int hashCode(){return 42;}
是一个完全有效的实现。