【问题标题】:Java: Unique 10 digit IDJava:唯一的 10 位数 ID
【发布时间】:2013-08-14 09:22:55
【问题描述】:

我需要在 Java 中生成一个唯一的 10 位数 ID。以下是此 ID 的限制:

  • 仅限数字
  • 最多 10 位数字
  • 每秒最多可以创建 10 个不同的 ID
  • 必须是唯一的(即使应用程序重新启动)
  • 无法在数据库中保存数字
  • 尽可能快地不要给系统增加太多延迟

目前我发现的最佳解决方案如下:

private static int inc = 0;

private static long getId(){

    long id = Long.parseLong(String.valueOf(System.currentTimeMillis())
            .substring(1,10)
            .concat(String.valueOf(inc)));
    inc = (inc+1)%10;
    return id;
}

此方案存在以下问题:

  • 如果出于某种原因需要每秒创建 10 个以上的 ID,则此解决方案将不起作用。
  • 大约 32 年后,此 ID 可能会重复(这可能是可以接受的)

创建此 ID 的任何其他解决方案?

还有其他我没有想到的问题吗?

感谢您的帮助,

【问题讨论】:

  • 应用程序的多个实例可以同时运行吗?
  • 目前只有一个实例正在运行,但将来可能会运行。我们还有一个辅助实例,以防主实例出现故障,但其中只有一个(主实例或辅助实例)会同时运行。
  • 正如下面的一些答案所指出的,我的实现将在多实例或多线程环境中失败,因此假设将运行具有单线程的单个实例。
  • 如果不引入某种形式的通信(例如数据库、文件或 Web 服务),就不可能保证跨实例的唯一性。

标签: java unique


【解决方案1】:

这是对你的一个小改进,但应该是有弹性的。

基本上,我们使用当前时间(以毫秒为单位),除非它自上一个 id 以来没有滴答过,在这种情况下,我们只返回 last + 1

private static final long LIMIT = 10000000000L;
private static long last = 0;

public static long getID() {
  // 10 digits.
  long id = System.currentTimeMillis() % LIMIT;
  if ( id <= last ) {
    id = (last + 1) % LIMIT;
  }
  return last = id;
}

因为它应该以相对较短的循环速率管理高达每秒 1000 次。要延长循环速率(但缩短分辨率),您可以使用 (System.currentTimeMillis() / 10) % 10000000000L(System.currentTimeMillis() / 100) % 10000000000L

【讨论】:

  • 如果必须在同一秒内创建超过 10 个 ID,使用 (System.currentTimeMillis() / 100) 实际上可以解决问题,因为这永远不会是连续的。谢谢,;)
  • 请记住System.currentTimeMillis() 有一个最小分辨率。我发现它在 MS 系统上步进大约 15 毫秒,所以/100 可能不像你想象的那么流畅,尽管这个算法会为你处理。
  • 我正在考虑使用/100,我刚刚看到一个问题: 失败时的简单示例: time: 1376479263900 id: #3764792639 time: 1376479263950 id: #3764792640 time: 1376479264000 id: # 3764792641 时间:1376479264050 id:#3764792640(重复)
  • 如果在第二个 1999999999 中创建了多个 id,这可能会出现问题,但直到 2033 年仍然没有问题(足够好)谢谢,:)
【解决方案2】:

这可能是一个疯狂的想法,但它是一个想法:)。

  • 首先生成 UUID 并获取它的字符串表示形式 java.util.UUID.randomUUID().toString()
  • 第二次将生成的字符串转换为字节数组(byte[]

  • 然后将其转换为长缓冲区:java.nio.ByteBuffer.wrap( byte digest[] ).asLongBuffer().get()

  • 截断为 10 位

不确定该方法的唯一性,但我知道您可以依赖 UUID 的唯一性,但尚未检查它们的唯一性如何转换并截断为 10 位长的数字。

示例取自JavaRanch,也许还有更多。

编辑:由于您仅限于 10 位数字,因此简单的随机生成器对您来说就足够了,请查看 SO:Java: random long number in 0 <= x < n range

上的问题/答案

【讨论】:

  • UUIDs are not guaranteed to be unique。虽然得到两个相同的 UUID 的概率很小。
  • 没错,但正如我所写的'你可以依赖它们的独特性',而不是它们是独一无二的:)
【解决方案3】:
private static AtomicReference<Long> currentTime = new AtomicReference<>(System.currentTimeMillis());

public static Long nextId() {
    return currentTime.accumulateAndGet(System.currentTimeMillis(), (prev, next) -> next > prev ? next : prev + 1) % 10000000000L;
}

【讨论】:

  • 请编辑您的答案以正确格式化代码。另外,添加一些解释
【解决方案4】:

什么意味着它必须是独一无二的?甚至跨越更多当前正在运行的实例?它会破坏您的实施。

如果它必须在整个宇宙中是唯一的,最好的解决方案是使用 UUID,因为它是经过数学证明的标识符生成器,​​因为它会在每个宇宙中生成唯一值。不太准确的数字会给您带来冲突。

当只有一个并发实例时,您可以以毫秒为单位获取当前时间,并使用增量解决 10ms 问题。如果您牺牲适当数量的最后一个位置,您可以在一毫秒内获得多个数字。我会定义精度 - 我的意思是你每秒需要多少唯一数字。使用这种方法,您将无需任何持久性即可解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 2012-03-18
    • 2012-06-23
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    相关资源
    最近更新 更多