对于java中的唯一id,此代码是线程安全的吗

对于java中的唯一id,此代码是线程安全的吗,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有一个简单的代码,希望生成具有唯一id的对象 公共类测试{ 专用静态长计数器=0; 私人长id; 私人测试(){ //不要担心溢出 id=计数器++; } //此方法是否始终使用唯一id测试对象? 公共静态测试getTest(){ 返回新测试(); } 公共长getId(){ 返回id; } } 想知道多个线程是否调用了getTest方法所有testobject是否都有唯一的id?否,生成唯一id不是线程安全的。对象很可能会收到非唯一ID。您可以使用AtomicInteger/AtomicL

我有一个简单的代码,希望生成具有唯一id的对象

公共类测试{
专用静态长计数器=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。@xehpuk
final
yes,
volatile
no。这两个关键字在运行时都会产生预期效果,但代码不仅仅意味着可运行:它还意味着可读
volatile
告诉读取器该值将要更改。但是,它永远不会改变<代码>最终版
更合适。@jameslarge True。我的评论只是指线程安全<代码>最终版更有意义,在不处理并发性时更是如此。