1. 程式人生 > >七、單例模式

七、單例模式

1、定義:單例模式(Singleton),保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。

2、什麼時候用呢?

  • 資源共享的情況下
    應用程式 日誌應用,一般都用單例模式實現,這一般是由於共享的日誌檔案一直處於開啟狀態,因為只能有一個例項去操作,否則內容不好追加。     Web應用的 配置物件的讀取,一般也應用單例模式,這個是由於配置檔案是共享的資源。
  • 控制資源的情況下
     資料庫連線池的設計一般也是採用單例模式,因為資料庫連線是一種資料庫資源。資料庫軟體系統中使用資料庫連線池,主要是節省開啟或者關閉資料庫連線所引起的 效率損耗
,這種效率上的損耗還是非常昂貴的,用單例模式來維護,就可以大大降低這種損耗。      多執行緒的執行緒池的設計一般也是採用單例模式,這是由於執行緒池要方便對池中的執行緒進行控制。   3、好處
  • 保證唯一例項
  • 可以嚴格地控制客戶怎麼訪問它。對唯一例項的受控訪問

4、實現思路

  • 讓類自己儲存它唯一的例項
  • 構造方法私有化
  • 提供一個訪問該唯一例項的方法

5、程式設計實現

  有很多種程式設計實現方式,這裡介紹兩種經典的:懶漢式、餓漢式

  1)懶漢式,顧名思義,不著急例項化自己,等第一次用到的時候再例項化

    a.最基本的情況

public class Singleton {
       private static Singleton single=null;//內部儲存自己的例項
       private Singleton(){} //構造方法私有化,保證只有自己能例項化自己
       // 靜態工廠方法
       public static Singleton getInstance(){ //提供一個訪問自身例項的方法
              if (single==null) {
                     single=new Singleton();     //若這個例項不存在,則建立它
              }
              return single;
       }
}

  評價:在多執行緒的情況下,這是不安全的,考慮多執行緒的安全問題,有以下三種改進方式

 

    b. 在getInstance的方法上加同步

public class Singleton {
       private static Singleton single=null;
       private Singleton(){} 
       public static synchronized Singleton getInstance(){
              if (single==null) {
                     single=new Singleton();     
              }
              return single;
       }
}

  評價:就多了一個同步的“synchronized”關鍵字,同步方法,別的呼叫不會進入到該方法,如此保證唯一性

  不足:同步是針對方法的,以後每次呼叫該方法時(即使已經建立了例項),也會進行同步,造成不必要的同步開銷。【不推薦】

 

    c. 雙重檢查鎖定

public class Singleton {
       private static Singleton single=null;
       private Singleton(){}
       public static Singleton getInstance(){ 
              if (single==null) {
                     synchronized (Singleton.class) {
                           if (single==null) {
                                  single=new Singleton();    
                           }
                     }
              }
              return single;
       }
}

  評價:先判斷例項是否存在,不存在的情況下,使用同步鎖,再檢查例項是否存在,不存在則建立。

  改進之處:只有在例項不存在的情況下,才同步,減少了不必要的同步開銷

 

    d. 靜態內部類【推薦】

public class Singleton {
       private Singleton(){}
       private static class LazyHolder{
              private static final Singleton INSTANCE=new Singleton();
       }
       public static final  Singleton getInstance(){   
              return LazyHolder.INSTANCE;
       }
}

  評價:在靜態內部類中例項化,利用了類載入機制,不存在多執行緒併發的問題。不一樣在於,在內部類裡面去建立物件例項,只要應用中不使用內部類,JVM就不會去載入這個單例類,也就不會建立單例物件,從而實現懶漢式的延遲載入。

  唯一性的原理是什麼????

 

  2)餓漢式,聽這名字就很飢渴,被載入的時候就迫不及待把自己例項化了

public class Singleton {
	private Singleton(){}
	private static final Singleton SINGLETON=new Singleton(); //直接例項化自己
	public static  Singleton getInstance(){	
		return SINGLETON;
	}
}

在類建立的同時就已經建立好一個靜態的物件供系統使用,以後不再改變,所以天生是執行緒安全的。