微信搜尋:碼農StayUp
主頁地址:https://gozhuyinglong.github.io
原始碼分享:https://github.com/gozhuyinglong/blog-demos
1. 單例模式
單例模式(Singleton Pattern)是一種簡單的物件建立型模式。該模式保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
所以要實現單例模式,要做到以下幾點:
- 將構造方法私有化,杜絕使用構造器建立例項。
- 需要自身建立唯一的一個例項,並提供一個全域性訪問入口
2. 單例模式的幾種實現
對於單例模式有以下5種實現。
2.1. 懶漢式
該方式是使用synchronized
關鍵字進行加鎖,保證了執行緒安全性。
優點:在第一次呼叫才初始化,避免了記憶體浪費。
缺點:對獲取例項方法加鎖,大大降低了併發效率。
由於加了鎖,對效能影響較大,不推薦使用。
public class SingletonLazy {
/**
* 私有例項
*/
private static SingletonLazy instance;
/**
* 私有構造方法
*/
private SingletonLazy() {
}
/**
* 唯一公開獲取例項的方法(靜態工廠方法),該方法使用synchronized加鎖,來保證執行緒安全性
*
* @return
*/
public static synchronized SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
2.2 餓漢式
餓漢式是利用類載入機制來避免了多執行緒的同步問題,所以是執行緒安全的。
優點:未加鎖,執行效率高。
缺點:類載入時就初始化例項,造成記憶體浪費。
如果對記憶體要求不高的情況,還是比較推薦使用這種方式。
public class SingletonEager {
/**
* 私有例項,靜態變數會在類載入的時候初始化,是執行緒安全的
*/
private static final SingletonEager instance = new SingletonEager();
/**
* 私有構造方法
*/
private SingletonEager() {
}
/**
* 唯一公開獲取例項的方法(靜態工廠方法)
*
* @return
*/
public static SingletonEager getInstance() {
return instance;
}
}
2.3 雙重校驗鎖
利用了volatile修飾符的執行緒可見性(被一個執行緒修改後,其他執行緒立即可見),即保證了懶載入,又保證了高效能,所以推薦使用。
public class SingletonDCL {
/**
* 私有例項,volatile修飾的變數是具有可見性的(即被一個執行緒修改後,其他執行緒立即可見)
*/
private volatile static SingletonDCL instance;
/**
* 私有構造方法
*/
private SingletonDCL() {
}
/**
* 唯一公開獲取例項的方法(靜態工廠方法)
*
* @return
*/
public static SingletonDCL getInstance() {
if (instance == null) {
synchronized (SingletonDCL.class) {
if (instance == null) {
instance = new SingletonDCL();
}
}
}
return instance;
}
}
2.4 靜態內部類
該模式利用了靜態內部類延遲初始化的特性,來達到與雙重校驗鎖方式一樣的功能。由於需要藉助輔助類,並不常用。
public class SingletonInnerClass {
/**
* 私有構造方法
*/
private SingletonInnerClass() {
}
/**
* 唯一公開獲取例項的方法(靜態工廠方法)
*
* @return
*/
public static SingletonInnerClass getInstance() {
return LazyHolder.INSTANCE;
}
/**
* 私有靜態內部類
*/
private static class LazyHolder {
private static final SingletonInnerClass INSTANCE = new SingletonInnerClass();
}
}
2.5 列舉類
該方式利用了列舉類的特性,不僅能避免執行緒同步問題,還防止反序列化重新建立新的物件。這種方式是 Effective Java 作者 Josh Bloch 提倡的方式。
但由於這種編碼方式還不能適應,所以實際工作中很少使用。
public enum SingletonEnum {
INSTANCE;
public void method() {
System.out.println("列舉類中定義方法!");
}
}