《Head First设计模式》第五章笔记-单件模式
單件模式
定義:確保一個類只有一個實例,并提供全局訪問點。
編寫格式:
| 1 2 3 4 5 6 | public class MyClass{ ????private MyClass(){}//構造方法私有化 ????public static MyClass getInstance(){??//提供全局訪問點 ????????return new MyClass(); ????} } |
有一些對象其實我們只需要一個,比如線程池、緩存、對話框、處理偏好設置和注冊表的對象、日志對象。如果制造出多個實例,就會導致程序的行為異常、資源使用過量,或者不一致的結果等。
單件模式實現1:延遲實例化
懶漢式
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | public class Singleton{ ????private static Singleton uniqueInstance;//創建一個靜態變量來記錄Singleton類的唯一實例 ????//。。。其他實例變量 ????private Singleton (){}//私有構造方法 ????//使用getInstance()方法實例化對象 ????public static Singleton getInstance(){ ????????if(uniqueInstance==null){//判斷uniqueInstance是否為空,為空則創建實例 ????????????uniqueInstance=new Singleton(); ????????} ????????return uniqueInstance; ????} ????//...其余方法 } |
類圖:
“延遲實例化”在我們不需要這個實例的時候它將不會產生。
上面的方法的確實現了單件模式,但是在某些情況下將出現一些嚴重的問題,例如:
在多線程的情況下,可能會創建多個對象。怎么解決多線程單件問題呢?下面有三種方法:
單件模式實現2:通過synchronized關鍵字解決多線程問題
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Singleton { ????private static Singleton singleton; ????private Singleton(){} ????//synchronized關鍵字迫使每個線程在進入方法前,要先等候別的線程離開該方法 ????public static synchronized Singleton getInstance() ????{ ????????if(singleton ==?null) ????????{ ????????????singleton =?new Singleton(); ????????} ????????return singleton; ????} } |
同步(synchronized)可以解決多線程存在的問題,但是同步會降低性能,且第一次執行此方法時才真正需要同步,一旦設置好uniqueInstance變量,就不再需要同步這個方法了,之后每次調用這個方法,同步都是一種累贅。
建議:
1.如果getInstance()d的性能對應用程序不是很關鍵,則可以忽略同步帶來的性能下降問題。
2.同步一個方法可能會讓程序執行效率下降100倍,如果getInstance()是程序使用在頻繁運行的地方則不建議這樣使用。
3.如果應用程序總是創建并使用單件實例或創建運行時的負擔不太繁重,可以使用“急切實例化”創建實例,而不用“延遲實例化”的做法。
單件模式實現3:急切實例化
餓漢式
| 1 2 3 4 5 6 7 8 | public class Singleton{ ????//在靜態初始化器中創建單件,且保證了線程安全 ????private static Singleton uniqueInstance=new Singleton(); ????private Singleton(){} ????public static Singleton getInstance(){ ????????return uniqueInstance; ????} } |
利用這個做法,我們依賴JVM在加載這個類時馬上創建此唯一的單件實例。JVM保證在任何線程訪問uniqueInstance靜態變量之前,一定先創建此實例。
單件模式實現4:雙重檢查加鎖
使用雙重檢查加鎖(double-checked locking),首先檢查實例是否已經創建了,如果尚未創建,才進行同步。這樣一來,只有第一次會同步。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //在getInstance()中減少使用同步 //注意:雙重檢查加鎖不適用于java1.4以及之前的版本,因為Volatile關鍵字會導致雙重檢查加鎖失效 class Singleton { ????//Volatile修飾的成員變量在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。 ????//即阻止線程為了優化性能而保有變量的私有拷貝 ????private volatile static Singleton singleton; ????private Singleton(){} ????public static Singleton getInstance() ????{??????????? ????????if(singleton ==?null)//檢查實例,如果不存在就進入同步區塊 ????????{ ????????????//注意,只有第一次才徹底執行這里的代碼 ????????????synchronized(Singleton.class) ????????????{ ????????????????if(singleton ==?null)//進入區塊后,再檢查一次 ????????????????{ ????????????????????singleton =?new Singleton(); ????????????????} ????????????} ????????} ????????return singleton; ????} } |
其他問題:
在Java1.2之前,垃圾收集器有個bug,會造成當單件在沒有全局的引用時被當作垃級清除。
多個類加載器(class loader)可能會導致單件失效。
單件模式要點:
- 單件模式確保程序中一個類最多只有一個實例。
- 單件模式也提供訪問這個實例的全局點。
- 在Java中實現單件模式需要私有的構造器、一個靜態方法和一個靜態變量。
- 確定在性能和資源上的限制,然后小心地選擇適當的方案來實現單件,以解決多線程的問題(我們必須認定所有的程序都是多線程的)。
- 如果不是采用第五版的Java 2,雙重檢查加鎖實現會失效。
- 小心,你如果使用多個類加載器,可能導致單件失效而產生多個實例。
- 如果使用JVM1.2或之前的版本,你必須建立單件注冊表,以免垃圾收集器將單件回收。
總結
以上是生活随笔為你收集整理的《Head First设计模式》第五章笔记-单件模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你的代码是否按照高内聚、低耦合的原则来设
- 下一篇: leetcode203 移除链表元素