我根据“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/