【问题标题】:Using new Date() as unique identifier使用 new Date() 作为唯一标识符
【发布时间】:2013-08-01 00:11:00
【问题描述】:

想象一下,我有一个每秒创建 1000 个实体的进程。 对于这些实体中的每一个,我都称其为 setter:

newEntity.setDate(new Date());

1) 2 个实体是否有可能收到相同的日期?或者可以安全地假设我确实获得了日期字段的唯一标识符效果?

2) 如果问题 #1 的答案是:“是” - 让我们做一个小调整: 让我们创建一个函数:

public static synchronized Date getDate() {
     return new Date();
}

现在可以用了吗?

newEntity.setDate(getDate());

3) 怎么样

System.nanoTime()?

编辑 4) 怎么样:

public static synchronized Date getDate() {
     Thread.Sleep(1000);
     return new Date();
}

谢谢。

【问题讨论】:

  • new Date() 读取系统时钟 - 可以在同一毫秒内进行多次读取。同步不会改变这一点(除了使完成操作所需的时间稍微长一点)。不要使用日期作为唯一标识符。

标签: java date datetime unique uniqueidentifier


【解决方案1】:

一个简单的测试表明,对new Date() 的两次连续调用可以返回相同的日期。使方法同步不会有任何区别。

如果您只需要一个唯一的 ID,您可以使用 AtomicInteger counter 和 return counter.getAndIncrement(); 作为新 ID。

ps:使用System.nanotime() 也无济于事,因为分辨率取决于操作系统和处理器,并且通常足够低以至于两个连续调用也可以返回相同的结果。


编辑

您在同步方法中睡眠一秒钟的第四个建议可能会解决您的唯一性问题(尽管正如 yshavit 所指出的,javadoc 中没有任何内容可以保证这一点)。但是请注意,使用 Date 作为唯一 id 本身就是一个坏主意:日期是可变的,因此调用代码可以使用 setTime 方法(错误或故意)更改其 id。

最后,如果你真的希望你的 id 与日期相关,你可以使用一个 long 表示自纪元以来的毫秒数并跟踪现有的 id - 像这样:

private static final Set<Long> usedIds = new HashSet<> ();
public static synchronized long getUniqueId() {
    long millis;
    do {
        millis = System.currentTimeMillis();
    } while (!usedIds.add(millis));
    return millis;
}

【讨论】:

  • 睡眠一秒钟与问题的开始参数之一不一致,即该过程“每秒创建 1000 个实体”,这也毫无价值。如果每个实体都需要至少一秒钟的时间来创建,那么每秒创建 1000 个实体将是很困难的。
  • +1 表示“使方法同步不会有任何区别”!!
【解决方案2】:

Date 具有毫秒精度。所以这归结为,“是否有可能在一毫秒内调用两次new Date()?答案显然是肯定的。另外,System.currentTimeMillis()is not completely accurate to the millisecond,只会让问题变得更糟。

您最好使用来自AtomicInteger(或AtomicLong)的简单计数器。

此外,这是对“按合同设计”心态的一个很好的锻炼。 currentTimeMillis 和 nanoTime 的规范都没有说它们会返回唯一的数字,所以你不能假设它们会(事实上,nanoTime 的 Javadoc 明确表示“不保证值的变化频率” )。即使它们今天发生在您的计算机上(可能不会),当 CPU 在 5 年内变得更快并且您能够每秒调用一万亿次 nanoTime() 时会发生什么?

继续你的承诺(假设你相信承诺!),而不是你今天碰巧看到的。这通常是正确的,尤其是与时间或并发相关的任何事情。

【讨论】:

    【解决方案3】:

    1) 如果您的 CPU 足够快,是的,两个实体可能会收到代表 相同 时间的 不同 对象(即它不会按照您想要的方式工作)

    2) 同样,如果你的 CPU 足够快,它就不会工作。

    【讨论】:

      【解决方案4】:

      不幸的是 1. 不是一个好的解决方案
      你的提议都不符合规定。
      在同步方法中,您可以添加具有正确粒度(1 毫秒)的睡眠:无论如何都非常难看。
      您的其他建议。
      System.nanotime() 我想现在应该是你的 uuid,这么长。
      在这种情况下,解决方法可能是将延迟设置为 1 纳秒,并且:

      long start = System.nanotime();  
      while(start + delay < System.nanoTime());  
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-27
        • 1970-01-01
        • 2016-02-18
        • 2021-12-07
        • 1970-01-01
        相关资源
        最近更新 更多