【Java 單例模式】Java 單例模式在多執行緒環境中可能存在的問題
阿新 • • 發佈:2018-12-26
在多執行緒環境下,使用延遲載入的方式實現單例模式,會出現錯誤。
例如,使用如下方式實現單例類:
package study20170307;
/**
* Created by apple on 17/3/7.
*/
public class SingleJavaTest {
private static SingleJavaTest singleJavaTest = null;
public static SingleJavaTest getSingleJavaTest(){
if (singleJavaTest == null){
//模擬在建立物件之前做一些準備工作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleJavaTest = new SingleJavaTest();
}
return singleJavaTest;
}
}
建立執行緒類:
package study20170307;
import java.io.*;
/**
* Created by apple on 17/3/7.
*/
public class ThreadA extends Thread {
@Override
public void run() {
super.run();
System.out.println(SingleJavaTest.getSingleJavaTest().hashCode());
}
}
建立執行類:
package study20170307;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by apple on 17/3/7.
*/
public class Main {
public static void main(String[] args) {
ThreadA thread1 = new ThreadA();
ThreadA thread2 = new ThreadA();
ThreadA thread3 = new ThreadA();
thread1.start();
thread2.start();
thread3.start();
}
}
執行效果如圖所示:
說明單例類並沒有實現成功。
那麼如何對上述單例類進行修改呢,我們可以將單例類中物件建立的部分放在同步塊中,同時還要採用雙重判定的方式。此時單例類程式碼如下:
package study20170307;
/**
* Created by apple on 17/3/7.
*/
public class SingleJavaTest {
private static SingleJavaTest singleJavaTest = null;
public static SingleJavaTest getSingleJavaTest(){
if (singleJavaTest == null){
//模擬在建立物件之前做一些準備工作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (SingleJavaTest.class){
if (singleJavaTest == null)singleJavaTest = new SingleJavaTest();
}
}
return singleJavaTest;
}
}
這時執行效果如圖所示:
說明單例類成功。