微信搜索:碼農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("枚舉類中定義方法!");
}
}