Design Pattern —— Singleton

Design Pattern —— Singleton   強力推薦枚舉和類級內部類方式實現單例模式html

單例模式是開發中很是經常使用的一種模式,簡單的說,咱們但願一個類永遠都只有一個對象。java

主要有兩個用途:緩存

1.存儲一些進程內共享的值(不是很推薦,大部分狀況下仍是應該用局部變量,互相傳遞值的方式)安全

2.任什麼時候候都不變的操做性能

 

單例模式的實現目前已知的有五種:優化

1.餓漢式spa

2.懶漢式線程

3.雙重驗證code

4.類級內部類htm

5.枚舉

 

1、餓漢式

類加載時就建立好對象,以空間換時間。這樣外部調用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 }

優勢:節省運行時間

缺點:佔用空間

 

2、懶漢式

類加裝時不建立對象,直到須要使用時才建立。

 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 }

優勢:節省空間,若是一直不用,就不會建立

缺點:每次獲取實例都會進行判斷,看是否須要建立實例,浪費判斷的時間。且是因爲是線程安全的,因此會下降總體的訪問速度

 

3、雙重驗證

雙重驗證的單例模式,是懶漢式單例的一種優化方式。既實現線程安全,又可以使性能不受很大的影響。

定義:

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

 

4、類級內部類實現的方式。

那咱們能不能想到一個辦法,既讓第一次使用時才建立對象,又解決線程安全呢。

類級內部類的特色:

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 }

 

 5、枚舉實現單例

《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》

相關文章
相關標籤/搜索