GOF設計模式之1:單例設計模式,gof設計模式

來源:互聯網
上載者:User

GOF設計模式之1:單例設計模式,gof設計模式
1.單例設計模式核心作用:

保證一個類只有一個執行個體,並且提供了訪問該執行個體的全域訪問點

2.常見應用情境:
  • window的工作管理員
  • 項目中讀取設定檔一般也是一個單例模式
  • 資料庫連接池的設計也是採用單例模式,因為資料庫連接是一種資料庫資源
  • 作業系統的檔案管理系統,也是單例模式,一個作業系統只能有一個檔案系統
  • Application也是單例的應用(Servlet編程或者Android的Application類)
  • 在Spring中,每個bean預設也是單例的,這樣的有點兒事Spring容器可以管理
  • 在Servlet編程中每個Servlet也是單例的
  • 在Spring MVC和Struts1架構中控制器對象也是單例
3.單例模式的優點
  • 由於單例模式只生產一個對象,減少了系統開銷,當一個對象的產生需要的資源比較多的時候,比如讀取設定檔、產生其它依賴對象時,則可以在應用啟動的時候直接產生一個單例對象,然後永久駐存記憶體的方式來解決。
  • 單例模式可以在系統設定全域訪問點,最佳化共用資源的訪問。例如可以設計一個單例類,負責所有資料表的映射。
4.常見5中單例模式的實現方式:

主要

餓漢式:安全執行緒,調用效率高。但是不能延時載入

懶漢式:安全執行緒,調用效率不高。但是可以消極式載入

其它:

雙重檢鎖式:由於JVM底層內部模型的原因,偶爾會出現問題,不建議使用

靜態內部類式:安全執行緒,調用效率高,而且可以消極式載入

枚舉單例:安全執行緒,調用效率高,不可消極式載入

餓漢式的範例程式碼:

public class Singleton01 {    //類初始化的時候,立即載入這個對象(沒有延時載入的優勢)。載入類時,是安全執行緒的    private static Singleton01 instance = new Singleton01();    private Singleton01(){}    //方法沒有同步調用效率高    public static Singleton01 getInstance(){        return instance;    }}

 

餓漢式單例模式的代碼中,static變數會在類裝載的時候進行初始化,此時不會涉及到多個線程對象訪問該對象的問題。虛擬機器會保證只會裝載一次該類,肯定不會發生並發訪問的問題,因此可以省略synchronized關鍵字

問題:如果僅僅是載入本類,而不是要調用getInstance,甚至永遠都沒有調用,則會造成資源浪費。

懶漢式的範例程式碼

 1 package com.chunjiangchao.pattern.singleton; 2 /** 3  * 測試懶漢式單例模式 4  */ 5 public class Singleton02 { 6     //類初始化的時候,不初始化這個對象(延時載入,真正用的時候再建立)。 7     private static Singleton02 instance = null; 8     private Singleton02(){} 9     ////方法同步,調用效率低!10     public static synchronized Singleton02 getInstance(){11         if(instance == null)12             instance = new Singleton02();13         return instance;14     }15 }

 

要點:消極式載入,懶載入真正用到的時候才會選擇載入

問題:

資源使用率高了,但是每次調用getInstance()方法都要同步,並發效率較低。

雙重檢鎖實現

 1 package com.chunjiangchao.pattern.singleton; 2 /** 3  * 測試DCL(雙重檢鎖)單例模式 4  *  5  */ 6 public class Singleton03 { 7     //類初始化的時候,不初始化這個對象(延時載入,真正用的時候再建立)。 8     private volatile static Singleton03 instance = null; 9     private Singleton03(){}10     ////代碼塊同步,調用效率要比同步方法要快一些,由於JVM的原因在高並發的情況下會出現問題11     public static  Singleton03 getInstance(){12         if(instance == null){13             synchronized (Singleton03.class) {14                 if(instance == null)15                     instance = new Singleton03();16             }17         }18         return instance;19     }20 }

 

提高了執行 的效率,不必每次擷取對象的時候都要進行同步,只有第一次才會進行同步建立。

問題:

由於編譯器最佳化的原因和JVM底層內部模型原因,偶爾會出現問題,不建議使用。但是我們可以在instance前面添加volatile關鍵字,這樣就沒問題了。

靜態內部類實現方式:(懶載入方式)

 1 package com.chunjiangchao.pattern.singleton; 2 /** 3  * 靜態內部類單例模式 4  * 這種方式:安全執行緒,調用效率高,並且實現了延時載入! 5  */ 6 public class Singleton04 { 7     private Singleton04(){} 8     public static  Singleton04 getInstance(){ 9         return Inner.instance;10     }11     private static class Inner{12         private static final Singleton04 instance = new Singleton04();13     }14 }

 

外部類沒有static屬性,則不會像餓漢式那樣,上來就把對象造出來了

只有真正調用getInstance才會載入靜態內部類。載入類時是安全執行緒的。instance 是static final類型,保證了記憶體中只有這樣一個執行個體存在,而且只被賦值一次,從而保證了執行緒安全性。

兼并並發高效調用和消極式載入的優勢。

換一句戶說:靜態內部有具備餓漢式和消極式載入的優勢。

枚舉實現單例:

 1 package com.chunjiangchao.pattern.singleton; 2 /** 3  * 枚舉式實現單例模式(沒有延時載入) 4  */ 5 public enum Singleton05 { 6     instance;//這個枚舉元素,本身就是單例對象! 7     public void operation(){ 8         //添加需要的操作 9     }10 }

 

優點:實現簡單;枚舉本身就是單例。由JVM從根本上提供保障。避免反射和序列化的漏洞

缺點:無消極式載入

5.如何選用這五種單例模式?

單例對象佔用資源少,不需要消極式載入:

枚舉好於餓漢式

單例對象佔用資源大,需要消極式載入

靜態內部類好於懶漢式

6.問題

反射可以破解上面(不包含枚舉)的實現方式(防止的做法是在構造方法中手動拋出異常)

還原序列化可以破解(不包含枚舉)的實現方式

可以通過定義readResolve防止獲得不同對象。還原序列化的時候,如果對象所在的類定義了readResolve()方法(一種回調方法),返回自己建立的那個對象。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.