此代码线程对于java中的唯一ID是否安全?

时间:2015-01-29 06:51:09

标签: java multithreading concurrency

我有一个简单的代码,我希望用唯一的id生成对象。这是代码段

public class Test {

    private static long counter = 0;
    private long id;

    private Test() {
        // Don't worry about overflow
        id = counter++;
    }

    // Will this method always Test Object with unique id?
    public static Test getTest() {
        return new Test();
    }

    public long getId() {
        return id;
    }

}

想知道多个线程是否调用了getTest方法,所有TestObjects都有唯一的id吗?

3 个答案:

答案 0 :(得分:2)

它不是线程安全的,因为两个线程可以同时执行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;
    }
}

答案 1 :(得分:1)

不,生成唯一ID不是线程安全的。很可能会发生对象将收到非唯一ID。你可以使用AtomicInteger / AtomicLong在private static AtomicLong counter = (new AtomicLong())的构造函数中使这个工作(即counter.getAndIncrement())然后Test

它不是线程安全的原因是每个处理器/内核都有自己的一组寄存器,如果没有同步,变量可能在不同的处理器/内核中具有不一致的副本。即使在单处理器系统上,抢先式多线程也会引入同样的问题。在非抢占式线程系统中不需要同步。

答案 2 :(得分:0)

如果要锁定类级变量,也可以在构造函数中使用synchronize块(不是实例变量,因为实例变量不需要同步。一次只能有一个线程创建对象) 。 所以你也可以尝试这个作为你的构造函数。

private Test() {
    // Don't worry about overflow
    synchronized(Test.class){
    id = counter++;
    }
}