设置此参考线程是否安全



关于这段代码是否是线程安全的,我一直得到各种各样的答案。我在Java 8中工作。

private final Object lock = new Object();
private volatile Object reference = null;
public Object getOrCompute(Supplier<Object> supplier) {
    if (reference == null) {
        synchronised(lock) {
            if (reference == null) {
                reference = supplier.get();
            }
        }
    }
    return reference;
}

我的期望是,给定此类的一个新实例,对getOrCompute()的多次调用只会导致调用一个供应商,而该供应商的结果是对getOrCompute()的所有调用(以及未来调用(的结果。

它是安全的,因为在supplier.get()中所做的任何操作都不能随着对reference的赋值而重新排序。(或者更准确地说,当你对reference进行不稳定的读取时,它不能看起来被重新排序。(

锁提供了独占性,而易失性写/读语义提供了可见性。请注意,自从很久以前发布的Java5之后,这种情况才出现过,但你仍然会在互联网上找到过时的文章,讲述双重检查锁定(因为这是这个习惯用法的官方名称(是如何不起作用的。它们在当时是对的,但现在已经过时了。

然而,如果供应商提供了一个可变对象,那么它本身可能是不安全的。但那是另一回事。

同步不是线程安全的。它阻碍了线程同时访问对象,但它无法控制哪个线程在何时访问对象,也无法控制一旦访问对象,它会对对象做什么。同步一次只限制对一个线程的访问,首先访问它的线程可以先访问它。

在这种情况下,它所做的唯一事情就是阻止几个线程实例化对象。如果对象已经被实例化,它将被分发给任何线程想要它,而没有线程安全性。

想象一下,你有一个线程访问方法并实例化对象,它检索它,当它检索对象时,另一个线程正在尝试实例化它,这是不允许的,因为它存在,所以它可以直接跳到检索对象,就像第一个线程一样,这些线程现在可以同时修改对象,呃,不是线程安全的。但是,新对象的实例化是线程安全的,因为对象只能实例化一次。

最新更新