雙重檢驗鎖方式實現單例模式的原理是什麼?

單例模式大概是Java編程中最常用的設計模式之一了,之前也有文章說過什麼是單例模式,鏈接如下:

https://blog.csdn.net/weixin_39309402/article/details/98126883

雖然這篇文章中也分析瞭如何利用同步鎖機制保證懶漢式單例模式的線程安全問題,同步方法,同步代碼塊等,但都非最優的解決方法,今天我們就來講講什麼是雙重檢驗鎖方式實現單例模式,包括它的特點和原理。

/**
 * 雙重檢驗鎖方式實現單例模式
 */
public class DualLazySingleTon {
	// 靜態實例變量
	private volatile static DualLazySingleTon instance;

	// 私有化構造函數
	private DualLazySingleTon() {
		System.out.println(Thread.currentThread().getName() + "\t" + "進入構造方法");
	}

	// 靜態public方法,向整個應用提供單例獲取方式
	public static DualLazySingleTon getInstance() {
		if (instance == null) { //第1重判斷
			synchronized (DualLazySingleTon.class) {
				if (instance == null) { //第2重判斷
					instance = new DualLazySingleTon();	
				}
			}
		}
		return instance;
	}

}
/**
 * 查看雙重檢驗鎖方式實現單例模式在多線程環境下線程是否安全
 */
public class DualLazyMyThread extends Thread {

	@Override
	public void run() {
		System.out.println(DualLazySingleTon.getInstance().hashCode());
	}

	public static void main(String[] args) {

		DualLazyMyThread[] mts = new DualLazyMyThread[10];
		for (int i = 0; i < mts.length; i++) {
			mts[i] = new DualLazyMyThread();
		}

		for (int j = 0; j < mts.length; j++) {
			mts[j].start();
		}
	}
}

第一次判斷是否爲null:
第一次判斷是在Synchronized同步代碼塊外,理由是單例模式只會創建一個實例,並通過getInstance方法返回singleton對象,所以如果已經創建了singleton對象,就不用進入同步代碼塊,不用競爭鎖,直接返回前面創建的實例即可,這樣大大提升效率。

第二次判斷singleton是否爲null:
第二次判斷原因是爲了保證同步,假若線程A通過了第一次判斷,進入了同步代碼塊,但是還未執行,線程B就進來了(線程B獲得CPU時間片),線程B也通過了第一次判斷(線程A並未創建實例,所以B通過了第一次判斷),準備進入同步代碼塊,假若這個時候不判斷,就會存在這種情況:線程B創建了實例,此時恰好A也獲得執行時間片,如果不加以判斷,那麼線程A也會創建一個實例,就會造成多實例的情況。

所以,爲了滿足單例模式的要求,雙重校驗是必不可少的。

聲明變量時爲什麼要用volatile關鍵字進行修飾?

volatile關鍵字可以防止jvm指令重排優化,使用了volatile關鍵字可用來保證其線程間的可見性和有序性;

因爲對象的創建並非一步完成,而是需要分爲3個步驟執行的,比如:singleton = new Singleton();  

指令1:獲取singleton對象的內存地址
指令2:初始化singleton對象
指令3:將內存地址指向引用變量singleton

因爲Volatile禁止JVM對指令進行重排序,所以創建對象時會嚴格按照指令1-2-3的順序執行,假若如果沒有Volatile關鍵字,單線程環境下不會出現問題,但是在多線程環境下會導致一個線程獲得還沒有初始化的實例。比如
線程A正常創建一個實例,執行了1-3,此時線程B調用getInstance()後發現instance不爲空,因此會直接返回instance,但此時instance並未被初始化,所以需要用volatile關鍵字修飾。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章