java - 还有一个关于 "Double-Checked-Locking"的问题

标签 java multithreading concurrency jvm singleton

我根据“effect java”#83修改了“正常”DCL单例情况,如下。

import java.util.Date;

public class MySystem {
    private Date date = new Date();

    private MySystem() {};

    private static volatile MySystem instance;

    public Date getDate() {
        return date;
    }

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

但是当我运行它时,抛出NullpointerException的比例非常高。当我按如下方式修改它时,一切正常。为什么?

import java.util.Date;

public class MySystem {
    private Date date = new Date();

    private MySystem() {};

    private static volatile MySystem instance;

    public Date getDate() {
        return date;
    }

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

主要内容如下。很难弄清楚其中的区别。

public class Main {
    public static void main(String[] args) {
        new Thread() {
            public void run() {
                System.out.println(MySystem.getInstance().getDate());
            }
        }.start();

        new Thread() {
            public void run() {
                System.out.println(MySystem.getInstance().getDate());
            }
        }.start();
    }
}

最佳答案

当发生以下情况时,您会得到 NPE:

public static MySystem getInstance() {
    MySystem my = instance;
    if (my == null) {                            // (1) instance was null => my is null and synchronized block is entered.
        synchronized (MySystem.class) {
            if (instance == null) {              // (2) instance was updated from another thread and is not null anymore.
                instance = my = new MySystem();
            }
        }
    }
    return my;
}

您会注意到,在这种情况下,引用实例不会复制到my中,它仍为null。您可以尝试以下方法来验证:

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

关于java - 还有一个关于 "Double-Checked-Locking"的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55057719/

相关文章:

java - hibernate 条件 : inheritence: Get a list of only the root class entities

java - 在这个例子中使用ConcurrentMap.replace有什么意义

c# - 有没有办法在启动后将数据发送到 BackgroundWorker?

c++ - 在 C++ 中将方法放入缓冲区

java - 如何在几周内停止或崩溃 Android 应用程序?

java - 线程上可运行对象的受监督调用

java - 如何使用 Java 从 XML 文件中提取数据?

java - Viewmodel 无法创建类 Android Java MVVM 的实例

java - 当在 foreach 循环中找不到值时无法找出 println 语句

c# - 调用 Web 服务异步