如何在 Java 中创建 64 位唯一整数

How to create a 64 bit Unique Integer in Java

我需要在 Java 中创建一个 64 位唯一整数,以便降低冲突几率。该系统不是分布式的,所以不同计算机之间的冲突不是问题。

有什么办法,我们可以在 Java 中创建一个始终唯一的 64 位整数?

截至目前,我正在使用 -

long number = System.nanoTime();

这是在 Java 中生成 64 位唯一整数的正确方法还是我可以尝试其他方法?

更新:-

这样做怎么样?这会是独一无二的吗?

UUID number = UUID.randomUUID();
long uniqueNumber = number.timestamp();

你想得到唯一的ID,合适的方式(虽然是128位):

UUID.randomUUID();

64 位不太合适(可能会发生冲突*):

UUID.getLeastSignificantBits();
UUID.getMostSignificantBits();

要真正获得唯一 ID(如果它们对您的操作至关重要):

  1. 使用所有 ID 的集中存储
  2. 当您需要 ID 时,让这个集中式系统处理它 -> 数据库和自动递增值通常是最简单的方法

*碰撞 => 2 个或更多相等值

使用 HashSet in order to ensure uniqueness of the values you're storing. You can then check whether the insert was successful by checking what add returns. If the values have to be 'randomised' you can use your own algorithm, or check out SecureRandom.

Long getUniqueNumber(HashSet uniqueNumberSet) {
    Long unique = generateUniqueNumber();
    if(!uniqueNumberSet.add(unique)) { // handle collision }
    return unique;
}

正如Marc B所说,最好的方法是一个简单的long,它用零初始化并在每次需要新值时递增。

如果您需要并发性,或者如果性能根本不是问题,那么您可以按照 Loc Ha 的建议使用 AtomicLong;但是,如果你真的需要它是一个 long 而不是一个 int,那么我怀疑你会生成很多它们,所以你应该避免 AtomicLong 的额外开销,除非你确定你也需要并发。

System.nanoTime() 不是一个好主意,因为您无法保证连续两次调用它总是会产生不同的值。

编辑(涵盖有问题的更新)

不,不保证 UUID 的时间戳部分是唯一的,原因与 System.nanoTime() 不保证唯一的原因完全相同。如果 UUID 的时间戳是唯一的,那么就不需要 UUID 类型,我们只需要始终使用该时间戳部分即可。时间 总是 一种保证唯一性的糟糕方法。

如果您需要数字在一个进程中是唯一的,并且在重新启动之间保持稳健,您可以使用简单的 AtomicLong 和计时器。

private static final AtomicLong TS = new AtomicLong();
public static long getUniqueTimestamp() {
    long micros = System.currentTimeMillis() * 1000;
    for ( ; ; ) {
        long value = TS.get();
        if (micros <= value)
            micros = value + 1;
        if (TS.compareAndSet(value, micros))
            return micros;
    }
}

这将为您提供具有毫秒精度的唯一 "timestamp",但每毫秒只能处理 1000 个 ID,而不会超前于实际时间。这在重新启动时工作正常,因为时间会跳过以前的值(再次假设平均每秒少于一百万)