設計系統時,通常希望控制對象的用法,防止用戶復制對象或建立新實例。例如,你可以使用它創建一個連接池,每次程序需要往數據庫中寫入內容時才創建一個新連接的做法并不明智;相反,一個或一組已經在池中的連接就可以使用Singleton模式實例化。
Singleton模式常常和工廠方法模式一同使用,創建一個系統級資源,使用這個資源的代碼并不知道它的特殊類型。抽象窗口工具包(AWT)就是組合使用這兩個模式的典型例子。在GUI應用程序中,對每個應用程序實例,你一般只需要一個圖形元素的實例,如打印(Print)對話框或OK按鈕。 3、類圖 4、單例模式的運行機制 Singleton是一個無法實例化的對象。這種設計模式暗示,在任何時候,只能由JVM創建一個Singleton(對象)實例。如果實例不存在,你通過創建類的新實例的方法建立一個類來執行這個模式;如果存在類的一個實例,就只會返回那個對象的一個引用。 下面看看單例模式的幾種實現方式: 方式1:
方式2:
方式2就是我們說的:滯后初始化(Lazy Initialization)。為什么會有滯后初始化這種實現方式出現呢?我們可用看到在第一種實現方式中無法向單例模式的構造方法傳遞參數,而使用滯后初始化的方式,我們可用在調用getInstance()方法的時候向方法中傳遞參數。
凡事有好處必然有壞處,滯后初始化的一個弊病就是在多線程或分布式的環境下有可能出現混亂:
“有時在某些情況下,使用Singleton并不能達到Singleton的目的,如有多個Singleton對象同時被不同的類裝入器裝載;在EJB這樣的分布式系統中使用也要注意這種情況,因為EJB是跨服務器,跨JVM的。” --摘自www.jdon.com-《GoF 23種設計模式解析》
“在多線程環境下,我們無法保證一個方法能夠持續運行到結束,其他線程的方法才開始運行。因而可能存在這樣一種情形:兩個線程幾乎同時嘗試初始化單例類。假設第一個方法發現單例為空,而第二個方法在此刻開始運行,它也會發現該單例為空。接下來,這兩個方法都將對該單例進行初始化。” --摘自《Java設計模式》 那么在多線程的環境下我們怎么更安全的使用單例模式呢? 方式3: 《Java并發編程》一書建議使用屬于當前類的鎖進行同步,代碼如下:
在第一個線程開始滯后初始化的時候,如果有另一線程也準備開始初始化,這時候,第二個線程將停止執行,等待獲取對象classLock的鎖。當第二個線程獲取這個鎖并開始執行初始化的時候,它會發現該單例已不再為空(因為只存在該類的唯有實例,我們可以使用單個靜態鎖)。 或者:
另一個解決辦法是在getInstance()方法聲明中添加synchronized關鍵字:
posted on 2008-05-28 16:57 云淡風清 閱讀(741) 評論(0) 編輯 收藏 所屬分類: Design Patterns
Powered by: BlogJava Copyright © 云淡風清