java - 非 volatile 双重检查锁定,这可能吗?

标签 java volatile java-memory-model double-checked-locking

这是我的单例类。

静态 instance 字段不是 volatile 的,因此会出现重新排序/可见性问题。为了解决这个问题,实例 val 字段是最终的。由于实例是正确构造的,因此如果客户端看到实例,它们应该始终看到初始化的 val 字段。

    static class Singleton {
    private static Singleton instance;
    private final String val;
    public Singleton() { this.val = "foo"; }

    public static Singleton getInstance() {
        if (instance == null)
            synchronized (Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
            }
        }
        return instance;
    }
    public String toString() { return "Singleton: " + val; }
}

但是还有另一个问题 - 我有两个不 protected “实例”字段读取,可以(?)重新排序,以便客户端可能得到 null 而不是实际值:

public static Singleton getInstance() {
    Singleton temp = instance;
    if (instance != null) return temp;
    else { /* init singleton and return instance*/ }
}

为了解决这个问题,我觉得我可以引入局部变量:

public static Singleton getInstance() {
    Singleton temp = instance;
    if (temp == null)
        synchronized (Singleton.class) {
            if(instance == null) {
                instance = new Singleton();
                temp = instance;
        }
    }
    return temp;
}

这似乎解决了问题,因为只有一个未 protected 值读取,因此不会发生任何真正邪恶的事情。但是......我刚刚修改了程序流程而没有(几乎?)改变它的单线程语义。这是否意味着编译器可以撤消我的解决方法,因为此转换是安全的,并且如果不与 volatile 建立适当的先行发生关系,就无法使此代码正常工作?

最佳答案

我不确定是否真的会发生对同一变量的读取重新排序,但可以保证局部变量不受其他线程 Activity 的影响。即使没有发生这样的读取重新排序,此保证也与您读取时可能同时更新的每个变量相关:如果您读取一个值并将其存储到局部变量中,您可以确保局部变量的值不会之后不会突然改变。当然,如果该值是引用,则该保证不适用于引用对象的字段。

相关句子可以在JLS §17.4.1中找到:

Local variables (§14.4), formal method parameters (§8.4.1), and exception handler parameters (§14.20) are never shared between threads and are unaffected by the memory model.

所以答案是否定的,不允许编译器撤销引入局部变量的解决方法。

关于java - 非 volatile 双重检查锁定,这可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25443173/

相关文章:

java - 如何在线性时间内从大型 OSM map 构建具有邻接表的无向图

java - 通过示例理解 volatile 变量

java - JVM 在何处保存有关引用和对象类型的信息

java - 深入理解Java中的volatile

java - 线程内一致性

java - 我可以在 Java 代码中做什么来优化 CPU 缓存?

java - 如何对自定义 Jackson JsonSerializer 进行单元测试?

java - 为什么 Java 内存转储分析器中的 Heap total 与内存设置和 JVM 使用总量不对应?

java - volatile 变量是否需要同步访问?

Java 不稳定的并发性