使用新的Date()作为唯一标识符
想象一下,我有一个每秒创建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()
两次连续调用可以返回相同的日期。 使方法同步不会有任何区别。
如果你需要的只是一个唯一的ID,你可以使用AtomicInteger counter
并return counter.getAndIncrement();
对于新的ID。
ps:使用System.nanotime()
也无济于事,因为分辨率是os和处理器相关的,并且通常足够低,以至于两个连续的调用也可以返回相同的结果。
编辑
你的第四个建议是在同步方法中睡一秒钟可能会解决你的单一性问题(虽然正如yshavit指出的那样,javadoc中没有任何内容可以保证它)。 但请注意,使用Date作为唯一ID本身就是一个坏主意:日期是可变的,因此调用代码可以使用setTime
方法(错误或故意)更改其id。
最后,如果你真的希望你的id与日期相关,你可以使用自纪元以来的长代表毫秒并跟踪现有的id – 如下所示:
private static final Set usedIds = new HashSet<> (); public static synchronized long getUniqueId() { long millis; do { millis = System.currentTimeMillis(); } while (!usedIds.add(millis)); return millis; }
Date
具有毫秒精度。 所以这归结为“是否有可能在一毫秒内调用两次new Date()
?答案显然是肯定的。此外, System.currentTimeMillis()
并不完全准确到毫秒 ,这只会使问题变得更糟。
使用AtomicInteger
(或AtomicLong
)的简单计数器会更好。
另外,这是“按合同设计”心态的一个很好的练习。 currentTimeMillis
和nanoTime
的规范都没有说它们会返回唯一的数字,所以你不能假设它们会(事实上,nanoTime的Javadoc特别指出“不保证值的变化频率”)。 即使它们今天碰巧在你的计算机上(它们可能没有),当CPU在5年内变得更快并且你能够每秒调用nanoTime()
一万亿次时会发生什么?
继续你所承诺的事情(假设你相信这个承诺!),而不是你今天所遇到的事情。 这通常是正确的,但尤其是与时序或并发相关的任何事情。
1)如果你的CPU足够快,是的,有可能两个实体接收代表相同时间的不同对象(即它不会按照你想要的方式工作)
2)同样,如果您的CPU足够快,它将无法工作。
不幸的是1.不是一个好的解决方案
你提出的建议都不合适。
在synchronized方法中,您可以添加具有正确粒度(1毫秒)的睡眠:无论如何都非常难看。
你的其他提案。
System.nanotime()我想现在应该是你的uuid,所以很长。
在这种情况下,解决方法可能是将延迟设置为1纳秒并且:
long start = System.nanotime(); while(start + delay < System.nanoTime());