注意:我知道在java 5(2004年给出)之前,双重检查锁在java中会失败,即使你在“instance”字段中添加“volatile”。在 java 5 之后,volatile 语义已经适用于双重检查锁。我也知道,如果没有“volatile”,即使在 java5 之后,由于乱序执行,双重检查锁也会失败。但是,我的问题是:如何编写代码来证明(如果没有“易失性”,双重检查锁将失败)???
我读过很多文章说在java中双重检查锁会失败,所以我认为下面的代码试图获取SocketFactory的单例实例会失败(因为“实例”字段不是易失性的):</p>
private static SocketFactory instance = null;
private static SocketFactory getInstance() {
if (instance == null) {
synchronized (SocketFactory.class){
if (instance == null){
instance = new SocketFactory(); // line 1
}
}
}
return instance;
}
但是,问题是,如果上面的代码会失败,我该如何证明呢?我试着写下面的代码(我想,如果第 1 行将被重新排序,“实例”引用可能指向一个 SocketFactory 对象,其中“构造”字段为“假”):
import java.io.*;
import java.nio.*;
import java.nio.file.*;
public class TIJ_doubleCheckingLock {
static TIJ_doubleCheckingLock instance;
private Object lock;
private boolean constructed = false;
{
constructed = false;
}
private TIJ_doubleCheckingLock() {
try{
Thread.sleep(10000);
} catch(Exception e) {
}
constructed = true;
}
static TIJ_doubleCheckingLock getInstance() {
if (instance == null) {
synchronized (TIJ_doubleCheckingLock.class) {
try{
Thread.sleep(1000);
} catch(Exception e) {
}
if(instance == null) {
instance = new TIJ_doubleCheckingLock();
}
}
}
return instance;
}
public static void main(String args[]) {
class MyThread extends Thread {
@Override
public void run() {
TIJ_doubleCheckingLock instance = TIJ_doubleCheckingLock.getInstance();
String fileName = "TIJ_doubleCheckingLockResult.txt";
java.io.File file = new File(fileName);
try {
if(!instance.constructed) {
java.nio.file.Files.write(Paths.get(file.toURI()), (instance.constructed+"").
getBytes("utf-8"), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}
} catch (Exception e) {
}
}
}
Thread firstThread = new MyThread();
firstThread.start();
try{
Thread.sleep(5000);
} catch(Exception e) {}
for(int i=0;i<10;i++) {
Thread thread = new MyThread();
thread.start();
}
}
}
但我从未在 txt 文件中看到“假”。那么如何证明双重检查锁会失败呢?