設計模式千千萬,總是單例最常見。
單例模式的定義
保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
六種單例的創建方式
1.餓漢式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
優點: 基於類的加載機制,避免了多線程同步問題,加載速度快。
缺點: 在類加載的時候就完成初始化,沒有懶加載,如果沒有使用這個實例,會造成內存浪費。
2.懶漢式-線程不安全版
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
優點: 第一次調用是才初始化對象,避免浪費資源
缺點: 加載速度慢,線程不安全
3.懶漢式-線程安全版(synchronized加鎖)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
優點: 多線程中保證線程安全 缺點: 每次獲取對象實例,都需要進行同步,造成不必要的同步開銷。
4.雙重校驗鎖
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null){
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
優點: 線程安全,懶加載,減少同步開銷
缺點: 第一個獲取對象速度稍慢,但其在某些情況下也會出現失效的情況,並不是完美的方式。
這裏面使用了兩次判空:第一次爲了不必要的加鎖同步,第二次是確保在instance爲null的情況下才創建實例,避免多次創建。
方法中還是用了關鍵字volatile對變量進行修飾,有如下幾個作用:
1.在Java內存模型中volatile可以保證可見性,及防止程序指令重排序。
2.對象的創建分爲如下幾個步驟:
instance = new Singleton();
- 1.爲instance分配內存空間
- 2.初始化instance
- 3.將instance指向內存地址
如果不加volatile的話,程序的執行順序就可能變成1->3->2,多線程中就會導致線程獲取一個沒有初始化的實例。例如線程a 執行了1,3, 此時線程b調用getInstance()發現instance不爲空,返回instance,但此時instance還未初始化。
5.靜態內部類
public class Singleton {
private Singleton() {}
public static Singleton getInstance() {
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
第一次加載類的時候不會初始化instance,只有第一次調用getInstance()的時候纔會進行加載SingleHolder並初始化instance,保證線程安全,也能保證實例唯一,推薦使用這種方式。
6.枚舉
public enum Singleton {
INSTANCE;
public void doSomeThing(){}
}
默認枚舉單例的創建是線程安全的,並且任何情況下都是單例。
以上就是6中常見的單例創建形式,按需使用吧。
單例的使用場景
- 整個項目需要一個共享訪問點或者數據
- 創建一個對象需要耗費的資源太多,比如訪問數據庫資源等
- 工具類對象