1. 程式人生 > >【Java 單例模式】Java 單例模式在多執行緒環境中可能存在的問題

【Java 單例模式】Java 單例模式在多執行緒環境中可能存在的問題

在多執行緒環境下,使用延遲載入的方式實現單例模式,會出現錯誤。
例如,使用如下方式實現單例類:

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;
    }
}

這時執行效果如圖所示:
這裡寫圖片描述

說明單例類成功。