Singleton設計模式,確保全局只存在一個該類的實例。將構造器聲明爲private,防止調用(雖然仍是可使用反射來調用)。聲明一個靜態的類實例在類中,聲明一個公共的獲取實例的方法。這篇博文給出了簡單的實現方法,分析如何作到線程安全,整理了使用Singleton的壞處。java
方法一是線程安全的,在類被裝載的時候,就初始化這個成員,Java庫中Runtime就是用了這個方法。
方法二不是線程安全的。若是多個線程同時進入到函數中(臨界區),那麼會返回多個不一樣的實例。設計模式
代碼驗證安全
如下代碼驗證了線程不安全,即多線程的狀況下方法二不能保證真正的「單例」。經過打印每一個類的hashCode來顯示,類實例不惟一。多線程
class Singleton { private static Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { try { Thread.sleep(233); singleton = new Singleton(); } catch (Exception e) { e.printStackTrace(); } } return singleton; } } public class Main { public static void main(String args[]) { for (int i = 0; i < 10; i++) { new Thread(new Runnable() { public void run() { Singleton singleton = Singleton.getInstance(); System.out.println(singleton.hashCode()); } }).start(); } } }
解決方案ide
一種簡單的處理方法是,將getInstance聲明爲synchronized的,效率低,由於每個線程都在等待進入臨界區。函數
另外一種方法叫作Double Checked Locking(DCL),將公共變量聲明爲volatile(每次要使用這個變量的時候,從內存中取出來,保證各個線程能夠看到這個變量的修改)。單元測試
class Singleton { private volatile static Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { try { Thread.sleep(233); synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } catch (Exception e) { e.printStackTrace(); } } return singleton; } }
有啥壞處,別怪這個設計模式,都是全局變量的錯。測試
1, 全局變量線程
Singleton管理公共的資源,在代碼中的任何地方,只要調用Singleton的獲取實例的方法,就能夠獲取到Singleton的實例,能夠對這些公共資源的讀寫。這讓Singleton成爲了一個全局變量。設計
全局變量的壞處,也是Singleton的壞處。全局變量自有全局變量的使用情景和優勢,要分開兩面看待,這裏只講壞處並不是想說全局變量一無可取。
在分析全局變量的壞處以前,在[2]下面看到了一個特別有意思的比喻:
Using global state with your fellow programmers is like using the same toothbrush with your friends - you can but you never know when someone will decide to shove it up his bum.
我想這位老兄說出這個觀點,大概是用過異味的牙刷吧。爲什麼不用規範來約束一同使用全局變量的人呢?
這位老兄道出了全局變量的本質,任何人能夠用它作任何事,給整個程序帶來了極大的不肯定性。網上關於全局變量的壞處討論不少,下面整理了一些,雖然並不是都很壞:
2, 破壞了單一職責原則
定義:就一個類而言,應該僅有一個引發它變化的緣由
當一個類使用了Singleton的時候,它不只負責這個類須要完成的任務,還負責這個單一對象資源的建立和管理。這個類的函數作兩項任務,相關性低。
這一點算不上太壞。畢竟設計原則並不老是須要遵照的。
上面講了壞處,核心要義是避免將Singleton用做全局變量。Singleton的使用場景是什麼呢?
回到Singleton的本質做用上來,只須要一個這個類的實例。前面講這個設計模式破壞了單一職責原則,由於須要管理這個實例。
因此歸結起來使用這個設計模式的兩個緣由:
(1) 單個實例
(2) 實例的管理
在[1]中講了使用Singleton的一個具體例子。那就是日誌(log)。由於log和代碼的實質功能並不會產生耦合,因此是否開啓log對於系統的功能沒有太大的影響。