【问题标题】:How to create a 64 bit Unique Integer in Java如何在 Java 中创建 64 位唯一整数
【发布时间】:2019-02-04 21:10:11
【问题描述】:

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

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

到目前为止,我正在使用 -

long number = System.nanoTime();

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

更新:-

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

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

【问题讨论】:

  • 当然。 i = 0,然后是 i++,只要您需要一个新的。
  • 碰撞几率是什么意思?
  • @MarcB 或者从Long.MIN_VALUE 开始,让它持续更长的时间。
  • 因为nanoTime() 会给你以纳秒为单位的时间,这似乎是非常独特的。然后你可以做Integer unique64Integer = (int) number;
  • @Ascalonian 禁止泛型,永远不要使用 Integer,加上 ints 是 32 位...

标签: java random 64-bit long-integer uuid


【解决方案1】:

如果您需要数字在一个进程中是唯一的,并且在重新启动之间保持稳健,您可以使用简单的 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;
    }
}

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

【讨论】:

  • 感谢您的建议。在您的示例中,什么是微?是micros,对吧。
  • @david 微秒。
  • 哦,知道了。看起来你的建议中有一个类型。您正在使用micro 并初始化micros
【解决方案2】:

使用HashSet 以确保您存储的值的唯一性。然后,您可以通过检查 add 返回的内容来检查插入是否成功。如果必须“随机化”这些值,您可以使用自己的算法,或查看SecureRandom

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

【讨论】:

  • 非常好的解决方案!如果你想保证唯一的键,哈希表是要走的路,OP。
  • 如果他需要它是一个 long 而不是一个 int,那么他显然会生成数百万个,所以除了测试之外,hashset 完全不可能用于任何目的.
  • 另外,这不是问题的答案。
  • 我认为您的第一点是 OP 的选择问题。 OP 可能会增加一个 long,或者 OP 需要一种快速(通常为 O(1),最坏情况为 O(logn))的方法来检查插入时值的唯一性。
  • 如果它只需要在 JVM 中是唯一的,您可以使用 AtomicLong 而不是 HashSet。
【解决方案3】:

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

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

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

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

不,UUID 的时间戳部分不能保证是唯一的,原因与 System.nanoTime() 不能保证唯一的原因完全相同。如果 UUID 的时间戳是唯一的,则不需要 UUID 类型,我们将始终使用该时间戳部分。时间总是是保证唯一性的坏方法。

【讨论】:

    【解决方案4】:

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

    UUID.randomUUID();
    

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

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

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

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

    *collisions => 2 个或更多相等的值

    【讨论】:

    • 这样怎么样? UUID number = UUID.randomUUID(); long uniqueNumber = number.timestamp();这是独一无二的吗?
    • 如果你想使用时间戳,那么你原来的解决方案会更好。这一切都取决于您的用例。您需要该值的频率以及您会同时运行多个实例吗?另外,这个值是你非常依赖的东西吗?
    • UUID 的子序列在构造上没有唯一性保证! (例如,如果您使用版本 1 UUID,则您的前 64 位只是一个时间戳和一个常量)。如果您需要小于 128 位的 UID,则需要探索不同的算法(来自 IEEE 的 EID-64、Twitter 的雪花等)。
    猜你喜欢
    • 2023-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-21
    • 2010-10-26
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    相关资源
    最近更新 更多