java單例模式總結
常見安全的單例實現有如下幾種:
一、 餓漢模式(靜態初始化)
class Singleton{ private Singleton(){ } private static Singleton cache=new Singleton(); public static Singleton getInstance(){ return Internal.cache; } }
實現最為簡單,但是如果Singleton的任何一個靜態欄位或者靜態方法被呼叫則會初始化。執行緒安全有虛擬機器的保證,物件的例項化是在類載入的初始化階段。初始化的時機詳見:深入理解java虛擬機器p210
二、雙重檢查鎖(dcl)
class Singleton{ private Singleton(){ } private volatile static Singleton cache; public static Singleton getInstance(){ if(cache==null){ synchronized (Singleton.class){ if(cache==null){ cache=new Singleton(); } } } return cache; } }
雙重檢查鎖是為了解決資源初始化較慢或者資源較重的場景下延遲初始化,利用synchronized關鍵字保證執行緒安全。餓漢模式是利用虛擬機器本身保證類載入的的執行緒安全性。但是dcl本身每次都需要檢查該物件是否例項化,所以引出下面的模式
三、 延遲佔位類
class Singleton{ private Singleton(){ } private static final class Internal{ static Singleton cache=new Singleton(); } public static Singleton getInstance(){ return Internal.cache; } }
延遲佔位類結合前兩種的優勢,消除了同步並且實現了延遲初始化。延遲佔位類模式的執行緒安全也是由虛擬機器來保證的,這裡需要理解的是為什麼能延遲初始化。相比於餓漢模式,延遲佔位類模式可以實現呼叫getInstance方法才去初始化該類
四、列舉實現
effective java中的推薦做法。我找了一個jdk中的實現如下:
enum NaturalOrderComparator implements Comparator<Comparable<Object>> { INSTANCE; @Override public int compare(Comparable<Object> c1, Comparable<Object> c2) { return c1.compareTo(c2); } @Override public Comparator<Comparable<Object>> reversed() { return Comparator.reverseOrder(); } }
列舉本身更加安全,虛擬機器層面阻止了通過反射去例項化一個類導致單例破壞的場景。
最後
此外還有懶漢模式和懶漢模式直接加synchronized的,這種程式碼比較簡單,實際也沒使用的意義就不展開了。