單例模式-DoubleCheck

1.單例模式理解:是爲了滿足一些場景,一個對象只能創建一個實例對象的場景。
流程:
1.構造方法私有化,
2.聲明對象 位靜態
3.類方法返回實例化後的對象。

2.將單例模式分爲兩類 懶漢式和餓漢式:

懶漢式:特點在定義Singleton是就new

public class Singleton{
		private static Singleton singleton=new Singleton();
		private Singleton(){}
		public static Singleton newInstance(){
			 return singleton;
		}
}

優點:簡單,而且保證了線程安全,不管有多少個線程訪問都只返回一個Singleton實例化對象

餓漢式單例模式:
1.普通

public class Singleton{
		private static Singleton singleton;
		private Singleton(){}
		public static Singleton newInstance(){
				if(singleton==null){		
					 singleton=new Singleton();
				}		
				return singleton; 
		}
}

線程不安全:if判斷確實可以保證只創建一個Singleton的實例對象。
但是在多線程併發場景下,由於沒有加鎖,多個線程可能都會進入到if中,那麼這些線程就可以進行對象實例化操作產生多個對象。

	if(singleton==null){		
  		  //多個線程進入id判斷裏面,
		  singleton=new Singleton();
	}	

雙層檢驗鎖單例模式:

public class Singleton{
		private static volatile Singleton singleton;
		private Singleton(){}
		public static Singleton newInstance(){
			   if(singleton==null){
			   			//1
			 		synchronized(Singleton.class){
			 			  		//2
			 			  		if(singleton==null){
			 						
			 							singleton=new Singleton();
			 				   		}
			 			}
			     }
			     return singleton;//3
		}
}

按照上面的註釋:來分析上面的代碼:

1.在調用類方法newInstance的時候所有線程都可以進入//1中
2.多個線程中只有一個線程會拿到鎖 進入同步代碼塊
3.拿到鎖後要再次判斷當前對象引用是否指向實例,因爲在這個線程之前還會有別的線程拿到鎖執行同步代碼塊。

到此流程基本結束:還有幾個問題:

1.singleton爲什麼要用volatile修飾?
首先,synchronized 保證了只有一個線程對singleton進行實例操作,但是操作的對象是引用數據類型,換句話說該操作不是原子的。那麼久可能發生指令重排。

正常情況:實例化對象的流程:
	1.在堆上開闢空間
	2.屬性初始化
	3.將棧上空間指向堆。
	正常是1——>2——>3
	
	但是如果沒有volatile關鍵字就可能發生指令重排:
	假設 1——>3——>2
	如果沒有屬性的話沒有問題,
	
	一旦有了屬性,假設現在有兩個屬性:
	name=“hahaha”,
	age=12;
	由於3步驟先執行,singleton已經不爲空了,
	當有新的線程嘗試獲取Singleton實例,到了外層判斷,直接返回。
	導致的結果就是,有能屬性還沒有來的及初始化就直接返回了,或者初始化了name..

2.爲什麼要有雙重if判斷:

內部的if是保證只有一個Singleton實例化對象被創建。
外層的if實際上是爲了保證性能:
當Singleton已經被創建了,不進入內部,直接返回。

可以把這種機制:當做一個限量發售的鞋,
把多線程當做在排隊等待鞋的人。
當一個人進入後買了這雙鞋		實際上已經沒有這雙鞋了
通常做法是在門口立一個牌子,鞋已經售空 人看到這個牌子就可以直接走了
 相當於外部的i	f)。
 如果沒有這個牌子,外面的人就不知道鞋已經賣完,還在不斷排隊進入鞋店,浪費資源
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章