如何寫出一個好的單例模式

單例模式是設計模式中總容易理解,而且使用次數比較多的模式,每每在面試中會被問到。在這裏我簡述下本身的思路。但願能對你有所幫助。 ###懶漢式 單例模式面試

public class Single {
    private static Single instance;
    private Single () {}
    
    public static Single getInstance () {
      if (instance == null) {
        instance = new Single();
    }
  return instance;
  }
}
複製代碼

上面這種,是咱們衆所周知的,每每教科書上也是這麼寫的,可是這種是線程不安全的,那麼咱們來看下一個。設計模式

懶漢式2

public static synchronized Single getInstance() {
  if (instance == null) {
    instance = new Single(); 
  }
return instance;
}
複製代碼

這種相對第一種來講,就安全了不少,可是它並不高效。安全

雙重檢驗鎖

雙重檢驗鎖模式(double checked locking pattern),是一種使用同步塊加鎖的方法。被稱其雙重檢驗鎖。是由於會有兩次檢驗instance == null,一次是在同步塊外,一次是在同步塊內。bash

public static Single getInstance () {
  if(instance == null) {
    synchronized (Single.class) {
      if(instance ==null) {
        instance = new Single();
      }
    }
   }
  return instance;
}
複製代碼

這樣是否是很完美了,但是還有問題,咱們來看下 JVM 對instance = new Single()這句話作了什麼函數

  • 大概作了三件事: 1.給instance分配內存 2.調用Single的構造函數來初始化成員變量 3.將instance對象指向給分配的內存 JVM的即時編譯器中存在指令重排序的優化。這樣就會致使上邊的第二步和第三步的實行順序不肯定。最終的執行順序多是 1-2-3 也多是 1-3-2。若是是後者,則在 3 執行完畢、2 未執行以前,被線程二搶佔了,這時 instance 已是非 null 了(但卻沒有初始化),因此線程二會直接返回 instance,而後使用,而後瓜熟蒂落地報錯。
public class Single() {
   private volatile static Single instance; // 聲明成 volatile
   private Single () {}
   public static Single getInstance () {
     if (instance == null) {
       synchronized (Single.class) {
           if(instance == null) {
             instance = new Single();
           }
       }
     }
     return instance;
   }
}
複製代碼

餓漢式 static final field

public class Single{
    //類加載時就初始化
    private static final Single instance = new Single();
    
    private Single(){}

    public static Single getInstance(){
        return instance;
    }
}
複製代碼

靜態內部類 static nested class

public class Single {  
    private static class SingleHolder {  
        private static final Single INSTANCE = new Single();  
    }  
    private Single (){}  
    public static final Single getInstance() {  
        return SingleHolder.INSTANCE; 
    }  
}
複製代碼

枚舉 Enum

用枚舉寫單例實在太簡單了!這也是它最大的優勢。下面這段代碼就是聲明枚舉實例的一般作法。優化

public enum EasySingle{
    INSTANCE;
}
複製代碼
相關文章
相關標籤/搜索