4

想象一下,我有一个每秒创建 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();
}

谢谢。

4

4 回答 4

10

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

如果您只需要一个唯一的 ID,则可以使用AtomicInteger counterandreturn 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;
}
于 2013-07-31T12:51:41.223 回答
4

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

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

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

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

于 2013-07-31T12:53:12.257 回答
0

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

2) 同样,如果您的 CPU 足够快,它将无法工作。

于 2013-07-31T12:51:40.623 回答
0

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

long start = System.nanotime();  
while(start + delay < System.nanoTime());  
于 2013-07-31T13:09:50.177 回答