設計模式---單例設計模式
阿新 • • 發佈:2018-12-13
單例模式的定義:確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。
說白了就是,保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
從定義中,我們可以看出:
- 單例類只能有一個例項。
- 單例類必須自行建立自己的唯一的例項。
- 單例類必須給所有其他物件提供這一例項 ,向整個系統提供這個例項。
餓漢單例:
/**
* 餓漢
*/
public class HungrySingleton {
// 顧名思義:餓漢就是一開始就直接例項化
private static HungrySingleton sInstance = new HungrySingleton() ;
//私有化空構造方法
// 不允許外部例項化
private HungrySingleton() {
// TODO: init something,if needed!
}
//靜態方法返回單例類物件
public static HungrySingleton getInstance() {
return sInstance;
}
}
餓漢模式是執行緒安全的
,因為類載入時就會初始化單例物件,並且只初始化一次
。
餓漢式單例雖然在首次呼叫的時候快
,但是類載入時就會初始化單例物件,容易產生垃圾
。
可以與java.lang.RunTime對照著看:
懶漢模式:
/**
* 懶漢:首次呼叫的時候才會進行例項化
*/
public class LazySingleton {
private static LazySingleton sInstance;
//私有化空構造方法
private LazySingleton() {
}
//靜態方法返回單例類物件
public static LazySingleton getInstance() {
//懶載入
if (sInstance == null) {
sInstance = new LazySingleton ();
}
return sInstance;
}
}
PS: 執行緒不安全,因為getInstance()方法沒有做任何的同步處理。 因為是首次呼叫的時候才會例項化,所以相比餓漢式單例會比較節省資源。 由於執行緒不安全,所以我們可能就會想著加鎖,可是加鎖後面臨的問題就是每次外部呼叫getInstance()時效率會明顯下降。 像下邊這樣:
// 靜態方法屬於類,給靜態方法加鎖相當於把整個類都鎖住了
public synchronized static LazySingleton getInstance() {
//懶載入
if (sInstance == null) {
sInstance = new LazySingleton();
}
return sInstance;
}
這就成執行緒安全的懶漢模式了。(一般不會這麼做的)
雙檢鎖(DCL:Double Check Lock):
/**
* @author yuan
* @version 1.0.0
* @Description DCL
* @date 2018/10/4 17:11
*/
public class DCLSingleTon {
private static DCLSingleTon sInstance;
private DCLSingleTon() {
}
public static DCLSingleTon getInstance() {
// first check
if (null == sInstance) {
synchronized (DCLSingleTon.class) {
// second check
if (null == sInstance) {
sInstance = new DCLSingleTon();
}
}
}
return sInstance;
}
}
DCL:執行緒安全。相比加鎖後的懶漢式單例更加有效率。 剛開始我還在想:為什麼要判空兩次呢? 第一次判空後,如果為null就已經加鎖了呀!後來想了想確實兩次判空是有道理的,假如有這種情況: 執行緒A和執行緒B同時進行了第一次判空,都是null那麼自然就順利進入程式碼塊中,然而此時由於加鎖原因執行緒排隊阻塞,等待其中一個執行緒執行完後,另外一個進入synchronized塊中執行,此時如果沒有第二次判空,那麼就會重複例項化,執行緒就不安全了。而二次判空就可以完美解決這個問題。
靜態內部類單例:
/**
* @author yuan
* @version 1.0.0
* @Description 靜態內部類單例模式
* @date 2018/10/4 17:30
*/
public class StaticInnerClassSingleton {
private static StaticInnerClassSingleton sInstance;
public static StaticInnerClassSingleton getInstance() {
// 靜態內部類只有在外部有人使用的時候才會進行載入,並不是和外部類一起載入的。(懶載入)
return SingleClass.STATICINNERCLASSSINGLETON;
}
//靜態內部類
private static class SingleClass {
private static final StaticInnerClassSingleton STATICINNERCLASSSINGLETON = new StaticInnerClassSingleton();
}
}
靜態內部類只有在外部有人使用的時候才會進行載入,並不是和外部類一起載入的。(懶載入) 靜態內部類中的靜態變數是通過類載入器初始化的,所以執行緒安全。