歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 單例模式(Singleton Pattern)

單例模式(Singleton Pattern)

日期:2017/3/1 10:09:57   编辑:Linux編程

單例模式確保一個類只有一個實例,並提供一個全局訪問點。

某些對象我們只需要一個,比如線程池、緩存、注冊表等等。如果這些類擁有多個實例,可能會產生很多問題。

使用單例模式可以確保我們使用的這些全局資源只有一份。

一個經典的單例模式的實現:

  1. public class Singleton{
  2. private static Singleton uniqueInstance;
  3. private Singleton(){}
  4. public static Singleton getInstance(){
  5. if(uniqueInstance==null){
  6. uniqueInstance=new Singleton();
  7. }
  8. return uniqueInstance;
  9. }
  10. }
由於Singleton類沒有公共的構造方法,我們並不能直接創建這個類的實例,而是只能通過調用靜態的getInstance()方法來獲取對單例對象的一個引用。當調用getInstance()時,如果該類還沒有任何實例則創建一個實例並返回對它的引用,如果已存在一個實例,則直接返回該實例的一個引用。

這樣就確保了單例的類最多只能有一個實例。

多線程下的隱患
在多線程的情況下,如果兩個線程幾乎同時調用getInstance()方法會發生什麼呢?有可能會創建出兩個該類的實例。

我們可以將getInstance()方法變為同步方法來解決這個問題:

  1. public class Singleton{
  2. private static Singleton uniqueInstance;
  3. private Singleton(){}
  4. public static synchronized Singleton getInstance(){
  5. if(uniqueInstance==null){
  6. uniqueInstance=new Singleton();
  7. }
  8. return uniqueInstance;
  9. }
  10. }

性能問題

然而,事實上,我們只有在uniqueInstance為null的時候才需要進行同步,當這個類已經有實例之後就不存在多線程隱患了。

因此我們將getInstance()方法變為同步方法有可能很大程度的拖垮性能。

如果將getInstance()方法變為同步方法真的影響到了性能,我們可以選擇在靜態初始化時創建這個單例。

  1. public class Singleton{
  2. private static Singleton uniqueInstance=new Singleton();
  3. private Singleton(){}
  4. public static Singleton getInstance(){
  5. return uniqueInstance;
  6. }
  7. }

這樣自然也能確保單例。

問題是,前面的例子中都是在需要一個實例的時候在創建單例,這個例子中在類初始化時就創建了單例。如果這個對象非常耗資源,而程序中又一直沒有用到它,這樣便是在浪費資源了。

“雙重檢查加鎖”

  1. public class Singleton{
  2. private volatile static Singleton uniqueInstance;//volatile修飾被不同線程訪問和修改的變量
  3. private Singleton(){}
  4. public static Singleton getInstance(){
  5. if(uniqueInstance==null){
  6. synchronized(Singleton.class){//對整個類加鎖
  7. if(uniqueInstance==null){
  8. uniqueInstance=new Singleton();
  9. }
  10. }
  11. }
  12. return uniqueInstance;
  13. }
  14. }
這樣就可以在節省資源的同時確保正確性和高效性。只是實現方法有點不夠簡潔了。
Copyright © Linux教程網 All Rights Reserved