標籤:
單例類:
主要知識點:
1,單例類概念、特點
2,三種單例類懶漢,餓漢,雙重加鎖舉例,
3,懶漢、餓漢區別以及單例類的總結;
1,概念:
java中單例模式是一種常見的設計模式,單例模式分三種:懶漢式單例、餓漢式單例、雙重檢查加鎖單例三種。
單例模式有以下特點:
1、單例類只能有一個執行個體。//建構函式為private
2、單例類必須自己建立自己的唯一執行個體。
3、單例類必須給所有其他對象提供這一執行個體。//public方法
2,三種單例類:
餓漢式:
1 public class EagerSingleton { 2 3 private static EagerSingleton instance = new EagerSingleton(); 4 5 /** 6 7 * 私人預設構造子 8 9 */10 11 private EagerSingleton(){}12 13 /**14 15 * 靜態Factory 方法16 17 */18 19 public static EagerSingleton getInstance(){20 21 return instance;22 23 }24 25 }
例子中,在這個類被載入時,靜態變數instance會被初始化,此時類的私人建構函式會被調用。這時候,單例類的唯一執行個體就被建立出來了。餓漢式在裝載類的時候就建立對象執行個體。
餓漢式是空間換時間,當類裝載的時候就會建立類的執行個體,不管你用不用,先建立出來,然後每次調用的時候,就不需要再判斷,節省了已耗用時間。
懶漢式:
1 public class LazySingleton { 2 3 private static LazySingleton instance = null; 4 5 /** 6 7 * 私人預設構造子 8 9 */10 11 private LazySingleton(){}12 13 /**14 15 * 靜態Factory 方法16 17 */18 19 public static synchronized LazySingleton getInstance(){20 21 if(instance == null){22 23 instance = new LazySingleton();24 25 }26 27 return instance;28 29 }30 31
懶漢式單例類實現裡對靜態Factory 方法使用了同步化,以處理多線程環境。懶漢式在不急著建立對象執行個體。會一直等到馬上要使用對象執行個體的時候才會建立,在裝載對象的時候不建立對象執行個體。
懶漢式是時間換空間,就是每次擷取執行個體都會進行判斷,看是否需要建立執行個體,浪費判斷的時間。當然,如果一直沒有人使用的話,那就不會建立執行個體,則節約記憶體空間
由於懶漢式的實現是安全執行緒的,這樣會降低整個訪問的速度,而且每次都要判斷。
雙重檢查加鎖:(java5及以上的版本)
所謂“雙重檢查加鎖”機制,指的是:並不是每次進入getInstance方法都需要同步,而是先不同步,進入方法後,先檢查執行個體是否存在,如果不存在才進行下面的同步塊,這是第一重檢查,進入同步塊過後,再次檢查執行個體是否存在,如果不存在,就在同步的情況下建立一個執行個體,這是第二重檢查。這樣一來,就只需要同步一次了,從而減少了多次在同步情況下進行判斷所浪費的時間。使用“雙重檢查加鎖”的方式來實現,就可以既實現安全執行緒,又能夠使效能不受很大的影響
“雙重檢查加鎖”機制的實現會使用關鍵字volatile,它的意思是:被volatile修飾的變數的值,將不會被本地線程緩衝,所有對該變數的讀寫都是直接操作共用記憶體,從而確保多個線程能正確的處理該變數。
1 public class Singleton { 2 3 private volatile static Singleton instance = null; 4 5 private Singleton(){} 6 7 public static Singleton getInstance(){ 8 9 //先檢查執行個體是否存在,如果不存在才進入下面的同步塊10 11 if(instance == null){12 13 //同步塊,安全執行緒的建立執行個體14 15 synchronized (Singleton.class) {16 17 //再次檢查執行個體是否存在,如果不存在才真正的建立執行個體18 19 if(instance == null){20 21 instance = new Singleton();22 23 }24 25 }26 27 }28 29 return instance;30 31 }32 33 }
這種實現方式既可以實現安全執行緒地建立執行個體,而又不會對效能造成太大的影響。它只是第一次建立執行個體的時候同步,以後就不需要同步了,從而加快了運行速度。
提示:由於volatile關鍵字可能會屏蔽掉虛擬機器中一些必要的代碼最佳化,所以運行效率並不是很高。因此一般建議,沒有特別的需要,不要使用。也就是說,雖然可以使用“雙重檢查加鎖”機制來實現安全執行緒的單例,但並不建議大量採用,可以根據情況來選用。
3,餓漢式和懶漢式區別以及總結
兩種區別主要兩點
1、安全執行緒:
餓漢式是安全執行緒的,可以直接用於多線程而不會出現問題,懶漢式就不行,它是線程不安全的,如果用於多線程可能會被執行個體化多次,失去單例的作用。
如果要把懶漢式用於多線程,有兩種方式保證安全性,一種是在getInstance方法上加同步,另一種是在使用該單例方法前後加雙鎖。
2、資源載入:
餓漢式在類建立的同時就執行個體化一個靜態對象出來,不管之後會不會使用這個單例,會佔據一定的記憶體,相應的在調用時速度也會更快,
而懶漢式顧名思義,會消極式載入,在第一次使用該單例的時候才會執行個體化對象出來,第一次掉用時要初始化,如果要做的工作比較多,效能上會有些延遲,之後就和餓漢式一樣了。
結論:由結果可以得知單例模式為一個物件導向的應用程式提供了對象惟一的訪問點,不管它實現何種功能,整個應用程式都會同享一個執行個體對象。
附:
安全執行緒:
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程啟動並執行結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是安全執行緒的。或者說:一個類或者程式所提供的介面對於線程來說是原子操作,或者多個線程之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題,那就是安全執行緒的。
Java單例類