Java的單例模式常見的分為懶漢式、餓漢式、靜態內部類、枚舉
通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從而方便對實例個數額控制並節約系統資源。
餓漢式:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
特點:
在這個類初始化時就創建了對象, 每次調用都返回同一個對象。
餓漢模式是線程安全的,可以直接用於多線程而不會出現問題。但是不需要這個對象時,對象就會占用內存空間。
懶漢式:
public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if(instance == null){ instance =new Singleton(); } return instance; } }
特點:
在調用獲取對象的方法時判斷, 如果沒有這個對象才會創建。
這樣在多線程的環境下會存在線程安全問題,JVM出於對效率的考慮,是在happens-before原則內(out-of-order)亂序執行。
懶漢式線程安全問題解決方法:DCL模式(double-check-locking)
class Singleton { public static Bank instance = null; public Singleton(){ } //效率更高的、線程安全的懶漢模式 public static Singleton getInstance(){ //外面加一層判斷,若對象不為Null,就讓后面的線程直接返回對象,不用再排隊擠進去 if(instance == null){ synchronized (Singleton.class){//使用synchronized關鍵字,保證只有一次只有一個線程進入,創建實例對象 if(instance == null){ instance = new Singleton(); } } } return instance; } }
靜態內部類:
public class SingleTon{ private SingleTon(){} private static class SingleTonHoler{ private static SingleTon INSTANCE = new SingleTon(); } public static SingleTon getInstance(){ return SingleTonHoler.INSTANCE; } }
特定:
這是官方推薦的。外部類加載時並不需要立即加載內部類,內部類不被加載則不去初始化INSTANCE,故而不占內存。不僅能確保線程安全,也能保證單例的唯一性,同時也延遲了單例的實例化。
枚舉:
public enum SingleTon{ INSTANCE; public void method(){ //TODO } }
特點:
枚舉在java中與普通類一樣,都能擁有字段與方法,而且枚舉實例創建是線程安全的,在任何情況下,它都是一個單例。我們可直接以下面這種方式調用。
SingleTon.INSTANCE