使用Java中UUID的最高有效位进行碰撞的可能性


235

如果我正在使用Long uuid = UUID.randomUUID().getMostSignificantBits()发生碰撞的可能性。它会切掉最低有效位,所以有可能发生碰撞,对吗?

Answers:


213

根据文档,静态方法UUID.randomUUID()生成类型4 UUID。

这意味着六位用于某种类型信息,其余的122位是随机分配的。

分布了六个非随机位,其中UUID的最高有效一半分配了四个,而最低有效一半分配了两个。因此,您UUID的最重要的一半包含60位随机性,这意味着您平均需要生成2 ^ 30个UUID才能发生冲突(相比之下,完整UUID则为2 ^ 61)。

所以我说你很安全。但是请注意,正如Carl Seleborg提到的,对于其他类型的UUID绝对不是这样。

顺便说一句,通过使用UUID的最低有效部分(或仅使用SecureRandom生成随机长整型),您的情况会更好一些。


3
我不确定这是完全正确的-查看实现,很明显版本/变体信息不是存储在最高有效位中,而是存储在中间位置。
汤姆(Tom)

2
@RasmusFaber Tom的评论是正确的:对于六个最高有效位是类型信息,此处的答案不正确。确实有6位非随机数据,但4位标识版本4,另2位保留。四位和两位位于128位值中间附近的不同位置。请参阅Wikipedia文章
罗勒·布尔克



10

您最好只生成一个随机的long值,然后所有位都是随机的。在Java 6中,新的Random()使用System.nanoTime()加上一个计数器作为种子。

有不同级别的唯一性。

如果您需要在许多计算机上具有唯一性,则可以有一个中央数据库表来分配唯一的ID,甚至是批次的唯一的ID。

如果您只需要在一个应用程序中具有唯一性,则可以拥有一个计数器(或根据您的要求从currentTimeMillis()* 1000或nanoTime()开始的计数器)


7

使用时间YYYYDDDD(年份+一年中的天)作为前缀。这减少了表和索引中的数据库碎片。此方法返回byte[40]。我在混合环境中使用了该环境,其中Active Directory SID(varbinary(85))是LDAP用户的密钥,而应用程序自动生成的ID用于非LDAP用户。同样,每天交易表(银行业)中的大量交易不能使用标准Int类型的密钥

private static final DecimalFormat timeFormat4 = new DecimalFormat("0000;0000");

public static byte[] getSidWithCalendar() {
    Calendar cal = Calendar.getInstance();
    String val = String.valueOf(cal.get(Calendar.YEAR));
    val += timeFormat4.format(cal.get(Calendar.DAY_OF_YEAR));
    val += UUID.randomUUID().toString().replaceAll("-", "");
    return val.getBytes();
}

3
为什么不改用标准V1 UUID?
ShadowChaser
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.