对于java中的唯一id,此代码是线程安全的吗
我有一个简单的代码,希望生成具有唯一id的对象对于java中的唯一id,此代码是线程安全的吗,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有一个简单的代码,希望生成具有唯一id的对象 公共类测试{ 专用静态长计数器=0; 私人长id; 私人测试(){ //不要担心溢出 id=计数器++; } //此方法是否始终使用唯一id测试对象? 公共静态测试getTest(){ 返回新测试(); } 公共长getId(){ 返回id; } } 想知道多个线程是否调用了getTest方法所有testobject是否都有唯一的id?否,生成唯一id不是线程安全的。对象很可能会收到非唯一ID。您可以使用AtomicInteger/AtomicL
公共类测试{
专用静态长计数器=0;
私人长id;
私人测试(){
//不要担心溢出
id=计数器++;
}
//此方法是否始终使用唯一id测试对象?
公共静态测试getTest(){
返回新测试();
}
公共长getId(){
返回id;
}
}
想知道多个线程是否调用了getTest方法所有testobject是否都有唯一的id?否,生成唯一id不是线程安全的。对象很可能会收到非唯一ID。您可以使用AtomicInteger/AtomicLong来实现这一点(即,
专用静态AtomicLong计数器=(新的AtomicLong())
),然后在测试的构造函数中使用计数器.getAndIncrement()
它不是线程安全的原因是每个处理器/内核都有自己的寄存器集,如果不同步,变量在不同的处理器/内核中可能有不一致的副本。即使在单处理器系统上,抢占式多线程也会带来同样的问题。在非抢占式线程系统中不需要同步。这不是线程安全的,因为两个线程可以同时执行counter++并且您可能会得到意外的结果
您应该使用AtomicInteger:
public class Test {
private static AtomicLong counter = new AtomicLong(0);
private long id;
private Test() {
// Don't worry about overflow
id = counter.incrementAndGet();
}
// Will this method always Test Object with unique id?
public static Test getTest() {
return new Test();
}
public long getId() {
return id;
}
}
如果要锁定类级变量(不是实例变量,因为实例变量不需要同步。一次只能有一个线程创建对象),也可以在构造函数中使用同步块。
因此,您也可以尝试将其作为构造函数
private Test() {
// Don't worry about overflow
synchronized(Test.class){
id = counter++;
}
}
您需要将该方法标记为已同步,设想一个场景,多线程同时访问该方法。。。这绝对不是线程安全的。你有一个可变状态-“计数器”。而且。。。在并行分布式环境中生成保证的UUID不是一个简单的问题。这可能是一个严重的研究问题。但是您可以以非常高的概率生成UUID。它不是线程安全的,因为计数器+++
不是原子操作。因此,下面的答案正确地建议使用AtomicLong
。或者在这种情况下使用AtomicLong。id
可能是final
或volatile
。否则,某些线程可能会看到id为0而不是真实id。@xehpukfinal
yes,volatile
no。这两个关键字在运行时都会产生预期效果,但代码不仅仅意味着可运行:它还意味着可读volatile
告诉读取器该值将要更改。但是,它永远不会改变<代码>最终版
更合适。@jameslarge True。我的评论只是指线程安全<代码>最终版更有意义,在不处理并发性时更是如此。