設計模式中,最簡單不過的就是單例模式。先看看單例模式
原文:http://www.iteye.com/topic/575052
Singleton模式可以是很簡單的,它的全部只需要一個類就可以完成(看看這章可憐的UML圖)。但是如果在“對象建立的次數以及何時被建立”這兩點上較真起來,Singleton模式可以相當的複雜,比頭五種模式加起來還複雜,譬如涉及到DCL雙鎖檢測(double checked locking)的討論、涉及到多個類載入器(ClassLoader)協同時、涉及到跨JVM(叢集、遠程EJB等)時、涉及到單例對象被銷毀後重建等。
目的:
希望對象只建立一個執行個體,並且提供一個全域的訪問點。
圖6.1 單例模式的UML圖
結構是簡單的,但是卻存在一下情況;
1.每次從getInstance()都能返回一個且唯一的一個對象。
2.資源共用情況下,getInstance()必須適應多線程並發訪問。
3.提高訪問效能。
4.懶載入(Lazy Load),在需要的時候才被構造。
首先實現1中的單例模式A: [java] view plain copy 4.public class SingletonA { 5. 6. /** 7. * 單例對象執行個體 8. */ 9. private static SingletonA instance = null; 10. 11. public static SingletonA getInstance() { 12. if (instance == null) { //line 12 13. instance = new SingletonA(); //line 13 14. } 15. return instance; 16. } 17.}
這個寫法我們把四點需求從上往下檢測,發現第2點的時候就出了問題,假設這樣的情境:兩個線程並發調用Singleton.getInstance(),假設線程一先判斷完instance是否為null,既代碼中的line 12進入到line 13的位置。剛剛判斷完畢後,JVM將CPU資源切換給線程二,由於線程一還沒執行line 13,所以instance仍然是空的,因此線程二執行了new Signleton()操作。片刻之後,線程一被重新喚醒,它執行的仍然是new Signleton()操作。所以這種設計的單例模式不能滿足第2點需求。
下面我們繼續
實現2中單例模式B: [java] view plain copy 4.public class SingletonB { 5. 6. /** 7. * 單例對象執行個體 8. */ 9. private static SingletonB instance = null; 10. 11. public synchronized static SingletonB getInstance() { 12. if (instance == null) { 13. instance = new SingletonB(); 14. } 15. return instance; 16. } 17.}
比起單例A僅僅在方法中多了一個synchronized修飾符,現在可以保證不會出線程問題了。但是這裡有個很大(至少耗時比例上很大)的效能問題。除了第一次調用時是執行了SingletonKerriganB的建構函式之外,以後的每一次調用都是直接返回instance對象。返回對象這個操作耗時是很小的,絕大部分的耗時都用在synchronized修飾符的同步準備上,因此從效能上說很不划算。
實現3單例模式C: [java] view plain copy 4.public