溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java雙重檢查鎖問題如何解決

發(fā)布時間:2023-04-18 13:49:05 來源:億速云 閱讀:130 作者:iii 欄目:編程語言

今天小編給大家分享一下java雙重檢查鎖問題如何解決的相關(guān)知識點,內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

雙重檢查鎖由來

首先我們來看一下非線程安全的初始化單例模式

	public class UnsafeLazyInitialization {
		private static UnsafeLazyInitialization instance;

		public static UnsafeLazyInitialization getInstance(){
			if(instance == null){                           //1:  線程A執(zhí)行
				instance = new UnsafeLazyInitialization();  //2: 線程B執(zhí)行
			}
			return instance;
		}
	}

在 UnsafeLazyInitialization 類中,假設(shè)線程A執(zhí)行到代碼1的時候,線程B執(zhí)行到代碼2, 這時候線程A 可能 看到 instance 引用對象還沒有完成初始化。

對于 UnsafeLazyInitialization 類,我們可以對getInstance()方法做同步處理來實現(xiàn)來實現(xiàn)線程安全的延遲初始化,示例代碼如下:

	public static synchronized  UnsafeLazyInitialization getInstance(){
			if(instance == null){                           //1:  線程A執(zhí)行
				instance = new UnsafeLazyInitialization();  //2: 線程B執(zhí)行
			}
			return instance;
		}
	}

由于上述代碼對getInstance()方法做了同步處理,這樣可能導(dǎo)致同步程序開銷加大。 如果getInstance()被多個線程頻繁調(diào)用,將會導(dǎo)致程序執(zhí)行性能降低,反之如果不是被多個線程調(diào)用,那個這個getInstance()方法的延遲初始化方法將影響性能。

JVM 1.6之前 synchronized是重量級鎖,所以很耗費性能,所以人們想到了一個種雙重校驗鎖(Dobule-check Locking)的方案來提高性能,示例代碼如下:

	public class DoubleCheckedLocking {                                 //1、
		private static Instance instance;                               //2、
		public static Instance getInstance(){                          //3、
			if(instance == null){                                      //4、第一次檢查
				synchronized (DoubleCheckedLocking.class){              //5、枷鎖
					if(instance == null){                                //6、第二次檢查
						instance = new Instance();                       //7、問題的根源在這里
					}                                                    //8、
				}
			}
			return instance;
		}
	}

如上代碼所示:如果 步驟4、第一次檢查instance不為null,則就不需要執(zhí)行下面的加鎖操作,大大降低了synchronized 鎖帶來的性能問題。上面代碼看起來沒有任何問題。 1、多個線程視圖去創(chuàng)建新對象的時候,通過synchronized關(guān)鍵字可以保證只有一個線程創(chuàng)建對象成功。

2、如果instance 實例對象已經(jīng)被創(chuàng)建,則直接通過getInstatnce()方法獲取對象實例。

上面雙重校驗鎖問題

上面代碼看上去很完美,但是當(dāng)執(zhí)行步驟4的時候,instatnce!=null 的時候,instatnce 的引用對象有可能還沒有完成初始化。

問題的根源

上面代碼我們執(zhí)行到步驟7的時候,instance = new Instance(); ,創(chuàng)建了一個對象,這個創(chuàng)建對象的步驟可以分為三步,如下:

	memory = allocate()  //1.分配內(nèi)存空間memory
	ctorInstance(memory) //2, 初始化對象在內(nèi)存 分配內(nèi)存空間memory上初始化 Singleton 對象
	instance = memory //3、設(shè)置 instance 指向剛分配的內(nèi)存地址memory

上面三行代碼 2和3可能發(fā)生重排序,在(JTI編譯器上,這種重排序是真是發(fā)生的) 步驟2和步驟3發(fā)生重排序后執(zhí)行順序

	memory = allocate()  //1.分配內(nèi)存空間memory
	instance = memory //3、設(shè)置 instance 指向剛分配的內(nèi)存地址memory
									// 注意此時instance對象還沒有被初始化,但是instance的引用已經(jīng)不是null了。
	ctorInstance(memory) //2, 初始化對象在內(nèi)存 分配內(nèi)存空間memory上初始化 Singleton 對象

下面看一下多線程執(zhí)行順序

java雙重檢查鎖問題如何解決

java雙重檢查鎖問題如何解決

上述代碼第7行instance = new Instance(); 如果A線程發(fā)生指令重排序(2,3),那么另一個線程B有可能在4行代碼判斷 instance 不為空。線程B接下來訪問instance的引用對象,但是instance對象有可能還沒被A初始化完成。此時線程B可能訪問一個沒有初始化完成的對象,導(dǎo)致報空指針錯誤。

問題解決

1、不允許2、3進(jìn)行指令重排。 2、允許2、3進(jìn)行重排序,但是不允許其它線程看到重排序

基于volatile 的解決方案

基于上面代碼只需要在instance聲明時加上volatile關(guān)鍵字就可以,如下代碼

	public class DoubleCheckedLocking {                                 //1、
		private static volatile Instance instance;                               //2、
		public static Instance getInstance(){                          //3、
			if(instance == null){                                      //4、第一次檢查
				synchronized (DoubleCheckedLocking.class){              //5、枷鎖
					if(instance == null){                                //6、第二次檢查
						instance = new Instance();                       //7、問題的根源在這里
					}                                                    //8、
				}
			}
			return instance;
		}
	}

以上就是“java雙重檢查鎖問題如何解決”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI