1. 單例模式概述
單例模式用於創建一個實例的場景,例如線程池、常量池,Spring上下文等等
2. 單例模式關鍵點
- 構造函數私有
- 聲明靜態成員變量存儲實例
- 對外提供獲取實例的方法
3. 最簡單的單例模式
public class SimpleSingleton{
private SimpleSingleton(){}//私有構造函數
private static SimpleSingleton instance = new SimpleSingleton();
public static SimpleSingleton getInstance(){
return instance;
}
}
這種方式實現的單例是線程安全的,當有多個線程去調用getInstance()方法時,不會創建多個對象,因爲JVM在加載該類時,對於static修飾的靜態屬性,只能由一個線程執行,且只執行1次。
但是在分佈式系統中,每臺服務器都有一個JVM,該方式不適用。
最簡單的實現方式在類加載時就初始化實例,若想要實現在調用時初始化實例,則可以使用Double-check locking的方式實現。
4. 延遲創建的單例
public class Singleton{
private Singleton(){}
private volatile static Singleton instance = null;
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
之所以判斷兩次,是因爲ThreadA和ThreadB同時調用該方法時,都判斷爲空,在等待進入同步代碼塊,如果ThreadA先進入,實例化了一個對象,在同步代碼塊中不再次判斷的話,ThreadB也將創建一個對象。
成員變量使用volatile關鍵字修飾,表示在ThreadA實例化對象後,其他線程能夠立即獲取instance變量的最新值。
5.基於類初始化的單例
public class InstanceFactory{
private static class InstanceHolder{
public static Instance instance = new Instance();
}
public static Instance getInstance(){
return InstanceHolder.instance;
}
}