【问题标题】:Creating a unique timestamp in Java在 Java 中创建唯一的时间戳
【发布时间】:2012-02-29 18:26:17
【问题描述】:

我需要在 Java 中创建一个时间戳(以毫秒为单位),以保证在该特定 VM 实例中是唯一的。 IE。需要一些方法来限制 System.currentTimeMillis() 的吞吐量,以便它每毫秒最多返回一个结果。关于如何实现它的任何想法?

【问题讨论】:

  • 我不确定你是什么意思 throttling currentTimeMillis() 所以它每毫秒返回最多一个结果?如果您想要唯一的时间戳,您宁愿保证它在每次调用时返回不同的值,对吧?
  • 它们必须单调递增吗?它们与实际的时间有什么关系吗?它们在多次运行中是否必须是唯一的?

标签: java concurrency timestamp epoch throttling


【解决方案1】:

这将使时间尽可能接近当前时间而不会重复。

private static final AtomicLong LAST_TIME_MS = new AtomicLong();
public static long uniqueCurrentTimeMS() {
    long now = System.currentTimeMillis();
    while(true) {
        long lastTime = LAST_TIME_MS.get();
        if (lastTime >= now)
            now = lastTime+1;
        if (LAST_TIME_MS.compareAndSet(lastTime, now))
            return now;
    }
}

避免每毫秒一个 id 的限制的一种方法是使用微秒时间戳。即,将 currentTimeMS 乘以 1000。这将允许每毫秒 1000 个 id。

注意:如果时间倒退,例如由于 NTP 更正,时间只会以每次调用 1 毫秒的速度前进,直到时间赶上。 ;)

【讨论】:

  • 谢谢!正是我需要的!
  • 正确使用,这意味着即使在重新启动应用程序后,您也将拥有唯一的 ID。
  • 你不超过平均每毫秒1个或每毫秒1000个(取决于你的倍数是多少)这样当你重新启动时,id将大于在应用程序停止之前使用的最后一个 id。鉴于您可以根据需要制作任何因素,这应该不是问题。我使用纳米时间的基本 id。 ;)
【解决方案2】:

您可以使用System.nanoTime() 以获得更好的准确性

虽然我在下面尝试过,每次它给出不同的值,但可能不能保证它一直都是唯一的。

public static void main(String[] args) {
        long time1 = System.nanoTime();
        long time2 = System.nanoTime();
        long time3 = System.nanoTime();
        System.out.println(time1);
        System.out.println(time2);
        System.out.println(time3);
    }

另一种方法是使用AtomicInteger/AtomicLong 类作为唯一编号,如果时间对您不重要并且您只需要唯一编号,这可能是一个更好的选择。

【讨论】:

  • nanoTime 是单调的,但并不总是唯一的。你可以得到很多重复。例如在 Red Hat 和 Centos 5.x 上,分辨率是微秒,所以你会得到很多重复的值。
  • 感谢您的信息。我猜这取决于操作系统和机器。
  • 您可以使用 nanoTime 并检查它是否不同。 (类似于我的解决方案)nanoTime 是许多系统上的正常运行时间(以秒为单位)。
  • +1:为您回答同样的问题,因为您可以将 nanoTime 与 AtomicLong(不是 AtomicInteger)一起使用
【解决方案3】:

在寻找解决方案时,我遇到了 ULIB (通用唯一的可按字典顺序排序的标识符) https://github.com/huxi/sulky/tree/master/sulky-ulid/

它不长,但比 UUID 短。

一个 ULID:

  • 与 UUID/GUID 兼容 每毫秒 1.21e+24 个唯一 ULID(准确地说是 1,208,925,819,614,629,174,706,176)
  • 按字典顺序排序
  • 规范编码为 26 个字符的字符串,而不是 36 个字符的 UUID
  • 使用 Crockford 的 base32 以提高效率和可读性(每个字符 5 位)
  • 不区分大小写
  • 无特殊字符(URL 安全)

【讨论】:

    【解决方案4】:

    您可以使用System.nanoTime(),这是最精确的可用系统计时器,然后将其除以百万以获得毫秒。虽然没有正式保证它的更新频率,但我相信可以合理地假设它的更新频率(数量级)多于每毫秒一次。当然,如果您以小于毫秒的间隔创建整数时间戳,那么它们不可能都是唯一的。

    请注意,绝对值nanoTime() 是任意的。如果您想要绝对时间,请以某种方式对其进行校准,即在开始时将其与 currentTimeMillis() 进行比较。

    【讨论】:

      【解决方案5】:

      您能不能使用java.util.UUIDtimestamp()clockSequence()

      Method Summary
          int clockSequence() 
              The clock sequence value associated with this UUID.
          long timestamp() 
              The timestamp value associated with this UUID.
      

      更多详情:http://docs.oracle.com/javase/1.5.0/docs/api/java/util/UUID.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-26
        • 1970-01-01
        • 2014-04-17
        • 1970-01-01
        • 2012-03-01
        • 2021-05-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多