這是典型的餓漢式單例,Singleton類載入時就會建立instance例項,這樣就需要提前開銷一部分系統資源。如果該例項在後期未使用,豈不是浪費了系統資源。其它問題不存在
private Singleton() {}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
複製程式碼
懶漢單例模式只有在第一次使用時才會初始化單例,一定程度上能節約資源,但反應會稍慢;通過 synchronized 關鍵字,保證了在多執行緒情況下單例的唯一性,但是在單例被第一次初始化後,再呼叫getInstance() 方法還需要進行同步操作,這樣會造成不必的系統開銷。
private Singleton(){
}
private static Singleton instance;
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
複製程式碼
雙重檢查鎖定單例模式(Double Check Lock)在 getInstance() 中,首先對instance進行非空判斷,避免多餘的同步,這也解決了懶漢單例模式中每次同步的問題,接下來如果 instance為空則建立其例項,當然這一步需要保證同步操作。注意 instance = new Singleton();這行程式碼,它的執行可以分解為第三個步驟:
(1)為 instance 例項分配記憶體。
(2)執行 Singleton 建構函式來初始化 instance。
(3)將 instance 指向分配的記憶體。
但在JDK1.5前,上邊的(2)(3)無法保證按順序執行,如果按(1)(3)(2)順序,假如A執行緒執行完(3),(2)未執行就被切換到B執行緒,因為步驟(3)已經在A執行緒執行,則B執行緒直接取走了認為非空 instance,這就導致雙重檢查鎖定的判斷失效。
在JDK1.5後,只要這樣宣告 instance 例項:private volatile static Singleton instance;即新增 volatile 修飾符,這樣就可以保證 instance 每次都從主記憶體讀取,避免了上邊的問題,但會略影響效能。這種單例模式也是在第一次執行 getInstance() 時建立單例,但第一次反映稍慢。
private Singleton() { }
private volatile static Singleton instance;
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){//兩次判斷了instance==null,所以稱為雙重檢查
instance = new Singleton();
}
}
}
return instance;
}
複製程式碼
靜態內部類單例模式:這種方式只有在的第一次呼叫getInstance()方法時,虛擬機器才會載入 SingletonHolder 類,並初始化instance 例項,即保證了執行緒同步,也能保證單例的唯一性,相對雙重檢查鎖定單例模式簡單了許多,推薦使用這種方式來實現單例模式。
private Singleton(){}
private static Singleton getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
private static final Singleton instance = new Singleton();
}複製程式碼