創(chuàng)建模式之Singleton——單例模式
1、簡介作為對象的創(chuàng)建模式,單例模式確保某個類只有一個實例,而且自行實例化,并向系統提供這個實例,這個類稱為單例類。他有三個要點:
只能有一個實例
自行創(chuàng)建這個實例
自行向系統提供這個實例
2、使用場景及能解決的問題
當你只需要一個類實例時,Singleton才真正有用;如果類擁有幾個實例,使用Singleton就不再適用。
設計系統時,通常希望控制對象的用法,防止用戶復制對象或建立新實例。例如,你可以使用它創(chuàng)建一個連接池,每次程序需要往數據庫中寫入內容時才創(chuàng)建一個新連接的做法并不明智;相反,一個或一組已經在池中的連接就可以使用Singleton模式實例化。
Singleton模式常常和工廠方法模式一同使用,創(chuàng)建一個系統級資源,使用這個資源的代碼并不知道它的特殊類型。抽象窗口工具包(AWT)就是組合使用這兩個模式的典型例子。在GUI應用程序中,對每個應用程序實例,你一般只需要一個圖形元素的實例,如打印(Print)對話框或OK按鈕。
3、類圖
4、單例模式的運行機制
Singleton是一個無法實例化的對象。這種設計模式暗示,在任何時候,只能由JVM創(chuàng)建一個Singleton(對象)實例。如果實例不存在,你通過創(chuàng)建類的新實例的方法建立一個類來執(zhí)行這個模式;如果存在類的一個實例,就只會返回那個對象的一個引用。
下面看看單例模式的幾種實現方式:
方式1:


















方式2:

















方式2就是我們說的:滯后初始化(Lazy Initialization)。為什么會有滯后初始化這種實現方式出現呢?我們可用看到在第一種實現方式中無法向單例模式的構造方法傳遞參數,而使用滯后初始化的方式,我們可用在調用getInstance()方法的時候向方法中傳遞參數。
凡事有好處必然有壞處,滯后初始化的一個弊病就是在多線程或分布式的環(huán)境下有可能出現混亂:
“有時在某些情況下,使用Singleton并不能達到Singleton的目的,如有多個Singleton對象同時被不同的類裝入器裝載;在EJB這樣的分布式系統中使用也要注意這種情況,因為EJB是跨服務器,跨JVM的。” --摘自www.jdon.com-《GoF 23種設計模式解析》
“在多線程環(huán)境下,我們無法保證一個方法能夠持續(xù)運行到結束,其他線程的方法才開始運行。因而可能存在這樣一種情形:兩個線程幾乎同時嘗試初始化單例類。假設第一個方法發(fā)現單例為空,而第二個方法在此刻開始運行,它也會發(fā)現該單例為空。接下來,這兩個方法都將對該單例進行初始化。” --摘自《Java設計模式》
那么在多線程的環(huán)境下我們怎么更安全的使用單例模式呢?
方式3:
《Java并發(fā)編程》一書建議使用屬于當前類的鎖進行同步,代碼如下:

















在第一個線程開始滯后初始化的時候,如果有另一線程也準備開始初始化,這時候,第二個線程將停止執(zhí)行,等待獲取對象classLock的鎖。當第二個線程獲取這個鎖并開始執(zhí)行初始化的時候,它會發(fā)現該單例已不再為空(因為只存在該類的唯有實例,我們可以使用單個靜態(tài)鎖)。
或者:













另一個解決辦法是在getInstance()方法聲明中添加synchronized關鍵字:

5、使用注意事項
單例模式類不能實現Clonable接口,以防被克隆而產生多個實例









單例模式類不能實現Serializable接口,以防被序列化而產生多個實例
根據不同的執(zhí)行,你的Singleton類和它的所有數據可能被當作垃圾收集。因此,在應用程序運行時,你必須保證存在一個Singleton類的實時引用。
posted on 2008-05-28 16:57 云淡風清 閱讀(750) 評論(0) 編輯 收藏 所屬分類: Design Patterns