設計模式——單例模式的幾種寫法
一、單例模式
單例模式是一種建立型的模式,指某個類採用單例模式後,在這個類被建立後,只產生一個例項以供外部訪問,且提供一個全域性的訪問點。
單例模式在開發中具有相當大的重要性,並且程式碼實現相對簡潔。所以其是為數不多的在面試中會被問到且要求手擼程式碼的設計模式哦:)。
二、幾種單例的寫法及比較
1. 飽漢模式
package designpatterns.singleton; /** * Created by Olive on 2017/12/8. */ public class Singleton1 { private static Singleton1 instance; public static Singleton1 getInstance() { if (instance == null) { instance = new Singleton1(); } return instance; } }
這種模式下,可以做到延遲化載入,但是在多執行緒模式下會產生多個例項,可不就是很“飽”麼XD?此模式非執行緒安全,不推薦使用。
2. 飽漢模式改進
package designpatterns.singleton; /** * Created by Olive on 2017/12/8. */ public class Singleton2 { private static Singleton2 instance; public static synchronized Singleton2 getInstance() { if (instance == null) { instance = new Singleton2(); } return instance; } }
此模式將getInstance方法進行同步,看似解決了執行緒的安全問題,但是同步粒度太大,效率十分低下,不建議使用。
3. 餓漢模式
package designpatterns.singleton; /** * Created by Olive on 2017/12/8. */ public class Singleton3 { private static final Singleton3 instance = new Singleton3(); public static Singleton3 getInstance() { return instance; } }
此模式在類載入時就例項化物件,做到了執行緒安全,但是instance在類裝載時就例項化。但是想象一種場景,如果例項化instance非常得消耗資源,或者例項的使用並非那麼頻繁,我們想讓例項延遲載入,在我們需要使用的時候才被例項化,那這種時候此模式就很不合理了。這是一種十分耗費資源的粗暴的模式,不建議使用。
4. 雙重檢查鎖(Double-checked Locking)
package designpatterns.singleton;
/**
* Created by Olive on 2017/12/8.
*/
public class Singleton4 {
private volatile static Singleton4 instance;
public static Singleton4 getInstance() {
if (instance == null) {
synchronized (Singleton4.class) {
if (instance == null)
instance = new Singleton4();
}
}
return instance;
}
}
此模式將與第二種單例的模式有點類似,減少了同步的開銷。相對來說是一個合理的單例寫法,但是此模式也並不是完美的。我們知道類的例項化並不是一個簡單的操作,內部其實主要包含了以下步驟:分配記憶體,初始化,例項指向記憶體。那麼當我們在進入第二個if (instance == null)時,開始為例項分配記憶體,此時其他執行緒執行到第一個if (instance == null)時,instance並不為空,於是此執行緒將直接返回instance,然而此時的instance因為沒有例項化結束,返回的例項並不是完整的。這就會導致錯誤的發生,這種模式需要慎用。
5. 靜態內部類
package designpatterns.singleton;
/**
* Created by Olive on 2017/12/8.
*/
public class InnerSingleton {
// 靜態內部類
private static class GetInstance {
private static final InnerSingleton INSTANCE = new InnerSingleton();
}
public static final InnerSingleton getInstance() {
return GetInstance.INSTANCE;
}
}
此模式起到了延時載入的作用,只有顯示呼叫getInstance方法時,才會顯示裝載GetInstance類,從而例項化INSTANCE。此方法執行緒安全,推薦使用。
6. 列舉
package designpatterns.singleton;
/**
* Created by Olive on 2017/12/8.
*/
public class Animal {
}
public enum AnimalSingleton {
INSTANCE;
public Animal getAnimalSingleton(){
final Animal animal = new Animal();
return animal;
}
}
要生成Animal的單例可以呼叫AnimalSingleton.INSTANCE. getAnimalSingleton。這種模式也是一種執行緒安全的單例實現,但是列舉在開發中用的並不多,所以一般大概也許很少人會採用這種模式吧。