Design Pattern —— Singleton 強力推薦枚舉和類級內部類方式實現單例模式html
單例模式是開發中很是經常使用的一種模式,簡單的說,咱們但願一個類永遠都只有一個對象。java
主要有兩個用途:緩存
1.存儲一些進程內共享的值(不是很推薦,大部分狀況下仍是應該用局部變量,互相傳遞值的方式)安全
2.任什麼時候候都不變的操做性能
單例模式的實現目前已知的有五種:優化
1.餓漢式spa
2.懶漢式線程
3.雙重驗證code
4.類級內部類htm
5.枚舉
類加載時就建立好對象,以空間換時間。這樣外部調用EagerSingleton.getInstance()時,直接得到這個建立好的對象。
1 public class EagerSingleton { 2 private static EagerSingleton instance = new EagerSingleton(); 3 /** 4 * 私有默認構造子 5 */ 6 private EagerSingleton(){} 7 /** 8 * 靜態工廠方法 9 */ 10 public static EagerSingleton getInstance(){ 11 return instance; 12 } 13 }
優勢:節省運行時間
缺點:佔用空間
類加裝時不建立對象,直到須要使用時才建立。
1 public class LazySingleton { 2 private static LazySingleton instance = null; 3 /** 4 * 私有默認構造子 5 */ 6 private LazySingleton(){} 7 /** 8 * 靜態工廠方法 9 */ 10 public static synchronized LazySingleton getInstance(){ 11 if(instance == null){ 12 instance = new LazySingleton(); 13 } 14 return instance; 15 } 16 }
優勢:節省空間,若是一直不用,就不會建立
缺點:每次獲取實例都會進行判斷,看是否須要建立實例,浪費判斷的時間。且是因爲是線程安全的,因此會下降總體的訪問速度
雙重驗證的單例模式,是懶漢式單例的一種優化方式。既實現線程安全,又可以使性能不受很大的影響。
定義:
1.先不一樣步,進入方法後,先檢查實例是否存在,若是不存在才進行下面的同步塊,這是第一重檢查;
2.進入同步塊事後,再次檢查實例是否存在,若是不存在,就在同步的狀況下建立一個實例,這是第二重檢查。
這樣一來,就只須要同步一次了,從而減小了屢次在同步狀況下進行判斷所浪費的時間。
「雙重檢查加鎖」機制的實現會使用關鍵字volatile,簡單的說:被volatile修飾的變量的值,將不會被本地線程緩存,全部對該變量的讀寫都是直接操做共享內存,從而確保多個線程能正確的處理該變量。
1 public class Singleton { 2 private volatile static Singleton instance = null; 3 private Singleton(){} 4 public static Singleton getInstance(){ 5 //先檢查實例是否存在,若是不存在才進入下面的同步塊 6 if(instance == null){ 7 //同步塊,線程安全的建立實例 8 synchronized (Singleton.class) { 9 //再次檢查實例是否存在,若是不存在才真正的建立實例 10 if(instance == null){ 11 instance = new Singleton(); 12 } 13 } 14 } 15 return instance; 16 } 17 }
雙重驗證的方式雖然看上去很美,可是是不被推薦使用的。具體volatile的使用也是一個比較大的課題,有一篇很是好的文章推薦http://www.cnblogs.com/dolphin0520/p/3920373.html
那咱們能不能想到一個辦法,既讓第一次使用時才建立對象,又解決線程安全呢。
類級內部類的特色:
1.類級內部類的對象和外部類對象沒有依賴關係
2.類級內部類中能夠有靜態方法,此靜態方法只能調用外部類的靜態方法和成員變量
3.類級內部類只有在第一次使用時纔會加載
JVM在有些時候會隱式的去執行同步操做:
1.由靜態初始化器(在靜態字段上或static{}塊中的初始化器)初始化數據時
2.訪問final字段時
3.在建立線程以前建立對象時
4.線程能夠看見它將要處理的對象時
實現線程安全:能夠採用靜態初始化器的方式,它能夠由JVM來保證線程的安全性。
實現延遲加載:採用類級內部類,在這個類級內部類裏面去建立對象實例。只要不使用到這個類級內部類,那就不會建立對象實例。
1 public class Singleton { 2 3 private Singleton(){} 4 /** 5 * 類級的內部類,也就是靜態的成員式內部類,該內部類的實例與外部類的實例 6 * 沒有綁定關係,並且只有被調用到時纔會裝載,從而實現了延遲加載。 7 */ 8 private static class SingletonHolder{ 9 /** 10 * 靜態初始化器,由JVM來保證線程安全 11 */ 12 private static Singleton instance = new Singleton(); 13 } 14 15 public static Singleton getInstance(){ 16 return SingletonHolder.instance; 17 } 18 }
《effectJava》一書中重點推薦的實現單例的方式
1 public enum Singleton { 2 /** 3 * 定義一個枚舉的元素,它就表明了Singleton的一個實例。 4 */ 5 6 uniqueInstance; 7 8 /** 9 * 單例能夠有本身的操做 10 */ 11 public void singletonOperation(){ 12 //功能處理 13 } 14 }
枚舉單例,簡潔,提供序列化機制,防止多實例化,防止反射,是實現單例的最佳方案。
參考資料
http://www.cnblogs.com/dolphin0520/p/3920373.html violate詳解
http://www.cnblogs.com/java-my-life/archive/2012/03/31/2425631.html java與模式之單例模式
《effectJava》