Java 使用新日期()作为唯一标识符

Java 使用新日期()作为唯一标识符,java,date,datetime,unique,uniqueidentifier,Java,Date,Datetime,Unique,Uniqueidentifier,假设我有一个每秒创建1000个实体的过程。 对于这些实体中的每一个,我称之为setter: newEntity.setDate(new Date()); 1) 两个实体是否可能收到相同的日期?或者可以安全地假设我确实获得了日期字段的唯一标识符效果吗 2) 如果问题#1的答案是:“是”-让我们稍微调整一下: 让我们创建一个函数: public static synchronized Date getDate() { return new Date(); } 现在行吗 newEntit

假设我有一个每秒创建1000个实体的过程。 对于这些实体中的每一个,我称之为setter:

newEntity.setDate(new Date());
1) 两个实体是否可能收到相同的日期?或者可以安全地假设我确实获得了日期字段的唯一标识符效果吗

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();
}
谢谢。

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


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

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

如果您只需要一个唯一的ID,那么可以使用
AtomicInteger计数器
返回计数器.getAndIncrement()用于新ID

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


编辑

您的第四个建议是在同步方法中睡眠一秒钟,这可能会解决您的唯一性问题(尽管正如yshavit所指出的,javadoc中没有任何东西可以保证这一点)。但是请注意,使用日期作为唯一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;
}
private static final Set usedIds=new HashSet();
公共静态同步长getUniqueId(){
长毫;
做{
毫秒=System.currentTimeMillis();
}而(!usedIds.add(millis));
返回毫秒;
}

日期
具有毫秒精度。因此,这可以归结为,“是否可以在毫秒内调用两次
new Date()
?答案显然是肯定的。此外,
System.currentTimeMillis()
,这只会使问题变得更糟

最好使用
AtomicInteger
(或
AtomicLong
)中的一个简单计数器

此外,这是“契约式设计”思维的一个很好的练习。
currentTimeMillis
nanoTime
的规范都没有说它们将返回唯一的数字,因此您不能假设它们会返回唯一的数字(事实上,用于nanoTime的Javadoc特别指出,“不保证值的更改频率”)。即使它们今天碰巧出现在您的计算机上(可能没有),当CPU在5年内变得更快,并且您能够每秒调用
nanoTime()
一万亿次时,会发生什么


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

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

long start = System.nanotime();  
while(start + delay < System.nanoTime());  
long start=System.nanotime();
而(启动+延迟
new Date()
读取系统时钟-可以在同一毫秒内进行多次读取。同步不会改变这一点(除非使完成一项操作所需的时间稍微延长)。不要使用日期作为唯一标识符。睡眠一秒钟与问题的开始参数之一不符也不值得。该过程“每秒创建1000个实体”。如果每个实体至少需要一秒钟的时间来创建,则很难每秒创建1000个实体。+1使方法同步不会产生任何影响”!!