java 个未通过双重锁定检查的代码
java codes that fails double locking checking
注意:我知道在java5(2004年给出)之前,double checking lock会在java失败,即使你添加"volatile" 到 "instance" 字段。在 java 5 之后,volatile 语义适用于双重检查锁。我也知道 without "volatile", double checking lock will fail 即使在 java5 之后,由于乱序执行。但是,我的问题是:如何编写代码来证明(没有 "volatile" 双重检查锁会失败)???
我读过很多文章说双重检查锁会在 java 中失败,所以我认为下面的代码试图获取 SocketFactory 的单例实例,将会失败(因为 "instance"字段不可变):
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 行将被重新排序,"instance" 引用可能指向一个 "constructed" 字段为 "false" 的 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 文件中看到 "false"。
那么如何证明双重检查锁会失败呢?
双重检查锁定was broken in Java. Your code works fine with Java 5 and onwards. The JVM since got a new memory model。
您的代码还需要 volatile
关键字。
private static volatile SocketFactory instance;
你需要知道我的代码在synchronized中的区别:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* @author heyunxia (love3400wind@163.com)
* @version 1.0
* @since 2016-01-15 下午3:50
*/
public class SocketFactoryTest {
public static void main(String[] args) {
SocketFactoryTest test = new SocketFactoryTest();
test.run();
}
private static final int COUNTER = 20;
CyclicBarrier barrier = new CyclicBarrier(COUNTER);
public void run(){
for(int i=0; i<COUNTER; i++) {
new Thread(new Runnable() {
@Override
public void run() {
SocketFactory.getInstance(barrier);
}
}).start();
}
}
}
class SocketFactory {
private static SocketFactory instance = null;
public static SocketFactory getInstance(CyclicBarrier barrier) {
if (instance == null) {
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
synchronized (SocketFactory.class) {
// option 1
instance = new SocketFactory();
System.out.println(Thread.currentThread().getName() + "***");
/*
// option 2
if (instance == null) {
System.out.println(Thread.currentThread().getName() + "***");
instance = new SocketFactory();
}else {
System.out.println(Thread.currentThread().getName() + "-have already instanced...");
}*/
}
}
return instance;
}
}
注意:我知道在java5(2004年给出)之前,double checking lock会在java失败,即使你添加"volatile" 到 "instance" 字段。在 java 5 之后,volatile 语义适用于双重检查锁。我也知道 without "volatile", double checking lock will fail 即使在 java5 之后,由于乱序执行。但是,我的问题是:如何编写代码来证明(没有 "volatile" 双重检查锁会失败)???
我读过很多文章说双重检查锁会在 java 中失败,所以我认为下面的代码试图获取 SocketFactory 的单例实例,将会失败(因为 "instance"字段不可变):
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 行将被重新排序,"instance" 引用可能指向一个 "constructed" 字段为 "false" 的 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 文件中看到 "false"。 那么如何证明双重检查锁会失败呢?
双重检查锁定was broken in Java. Your code works fine with Java 5 and onwards. The JVM since got a new memory model。
您的代码还需要 volatile
关键字。
private static volatile SocketFactory instance;
你需要知道我的代码在synchronized中的区别:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* @author heyunxia (love3400wind@163.com)
* @version 1.0
* @since 2016-01-15 下午3:50
*/
public class SocketFactoryTest {
public static void main(String[] args) {
SocketFactoryTest test = new SocketFactoryTest();
test.run();
}
private static final int COUNTER = 20;
CyclicBarrier barrier = new CyclicBarrier(COUNTER);
public void run(){
for(int i=0; i<COUNTER; i++) {
new Thread(new Runnable() {
@Override
public void run() {
SocketFactory.getInstance(barrier);
}
}).start();
}
}
}
class SocketFactory {
private static SocketFactory instance = null;
public static SocketFactory getInstance(CyclicBarrier barrier) {
if (instance == null) {
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
synchronized (SocketFactory.class) {
// option 1
instance = new SocketFactory();
System.out.println(Thread.currentThread().getName() + "***");
/*
// option 2
if (instance == null) {
System.out.println(Thread.currentThread().getName() + "***");
instance = new SocketFactory();
}else {
System.out.println(Thread.currentThread().getName() + "-have already instanced...");
}*/
}
}
return instance;
}
}