歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

單例模式(Singleton Pattern)

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

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

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

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

  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