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