在剛學編程沒多久就據說過設計模式的大名,不過因爲當時仍是個不折不扣的菜鳥,並無去觸碰。直到在開始工做中對簡單的業務代碼較爲熟悉以後,才正式的接觸設計模式。當時最先接觸的設計模式是工廠模式,不過本文講的是單例模式,這裏就留着下篇文章中在講解。至於爲何先講解單例模式? 那是由於單例模式是設計模式中最簡單的... 。凡事總有個前後順序,因此就先易後難了。好了,廢話很少說了,開始進入正片。數據庫
說明:這裏說了的簡介就是真的 「簡介」。編程
設計模式是一套被反覆使用的、多數人知曉的、通過分類編目的、代碼設計經驗的總結。設計模式
使用設計模式是爲了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。安全
設計模式有23種類型。按照主要分類能夠分爲三大類:多線程
1、建立型模式性能
這些設計模式提供了一種在建立對象的同時隱藏建立邏輯的方式,而不是使用 new運算符直接實例化對象。這使得程序在判斷針對某個給定實例須要建立哪些對象時更加靈活。學習
2、結構型模式.net
這些設計模式關注類和對象的組合。繼承的概念被用來組合接口和定義組合對象得到新功能的方式。線程
3、行爲型模式設計
這些設計模式特別關注對象之間的通訊。
設計模式的六大原則
保證一個系統中的某個類只有一個實例並且該實例易於外界訪問。例如Windows界面的任務管理器就能夠看作是一個單例。
在程序中比較經常使用的是數據庫鏈接池、線程池、日誌對象等等。
最先咱們在學習單例模式的時候,基本都會接觸這兩種模式:餓漢式和飽漢式(懶漢式)。
那咱們先來看看這兩個模式的實現。
餓漢式
定義一個私有的構造方法,並將自身的實例對象設置爲一個私有屬性,並加上static和final修飾符,而後經過公共的靜態方法調用返回實例。
class SingletonTest1 { private SingletonTest1() { } private static final SingletonTest1 instance = new SingletonTest1(); public static SingletonTest1 getInstance() { return instance; } }
飽漢式
定義一個私有的構造方法,定義一個該類靜態私有的變量,而後定義一個公共的靜態方法,對該類的值進行空判斷,不爲空直接返回,不然從新構建一個。
class SingletonTest2 { private SingletonTest2() { } private static SingletonTest2 instance; public static SingletonTest2 getInstance() { if (instance == null) { instance = new SingletonTest2(); } return instance; } }
簡單的介紹了這兩種的模式,而後咱們再來看看這兩種模式的優缺點吧。
餓漢式
飽漢式
雖然 飽漢式能夠經過加上synchronized關鍵字保證線程安全。可是效率方法來講還不說是最優。
這裏在介紹下我的認爲在JDK1.5以前最優的兩種寫法,一種是靜態內部類,另外一種是雙重鎖檢查。
靜態內部類
定義一個私有的構造方法,定義一個該類私有靜態的內部類,而後在內部類中定義一個該類的靜態變量,而後經過公共的final修飾的靜態方法調用返回實例。
class SingletonTest4 { private SingletonTest4(){ } private static class SingletonTest5{ private static SingletonTest4 instance = new SingletonTest4(); } public static final SingletonTest4 getInstance(){ return SingletonTest5.instance; } }
由於該類的內部類是私有的,除了對外公佈的公共靜態方法getInstance(),是沒法訪問的。由於它是延遲加載,因此讀取讀取實例的時候不會進行同步,幾乎沒有性能的缺陷,並且仍是線程安全的,而且不依賴JDK的版本。
雙重鎖檢查
定義一個私有構造方法,經過volatile定義靜態私有變量,保證了該變量的可見性,而後定義一個共有的靜態方法,第一次對該對象實例化時與否判斷,不爲空直接返回,提高效率;而後使用synchronized 進行同步代碼塊,防止對象未初始化時,在多線程訪問該對象在第一次建立後,再次重複的被建立;而後第二次對該對象實例化時與否判斷,若是未初始化,則初始化,不然直接返回該實例。
class SingletonTest6 { private SingletonTest6() { } private static volatile SingletonTest6 instance; public static SingletonTest6 getIstance() { if (instance == null) { synchronized (SingletonTest6.class) { if (instance == null) { instance = new SingletonTest6(); } } } return instance; } }
這種模式在很長的一段時間內能夠說是最優的了,內存佔用低,效率高,線程安全,多線程操做原子性。可是有個缺點就是書寫麻煩,對新手不太友好。
JDK1.5以後出現了枚舉,而且完美支持單例模式,而且線程安全、效率高!可是這些不是最重要的,最重要的是書寫超級簡單!究竟有多簡單,看下面的示例應該就能夠了解一下了。。。
枚舉單例
enum SingletonTest7{ INSTANCE; }
對的,你沒看錯,就這點代碼,其它不須要了。。。
枚舉須要在JDK1.5以後的版本,它無償提供序列化機制,絕對防止屢次實例化,即便在面對複雜的序列化或者反射攻擊的時候。這種方法也被Effective Java做者Josh Bloch 所提倡。
單例模式的幾種使用就到這了,那麼咱們來總結下使用單例模式須要注意什麼(不包括枚舉)。
原創不易,若是感受不錯,但願給個推薦!您的支持是我寫做的最大動力!
版權聲明:
做者:虛無境
博客園出處:http://www.cnblogs.com/xuwujing
CSDN出處:http://blog.csdn.net/qazwsxpcm
我的博客出處:http://www.panchengming.com