上篇文章介紹了單例模式,多例模式,有不明白的同學可以點進去先觀看:
spring單例模式,多例模式,餓漢模式,懶漢模式(一)?
這篇文章重點介紹餓漢模式懶漢模式,
餓漢模式:在加載對象時候,對象就會建立執行個體,為所有spring配置檔案中定義的bean都是生成的一個執行個體,天生線程安全的,多線程的情況下也不會出現問題。
懶漢模式:在擷取對象第一次請求的時候,才會建立執行個體。本身是線程不安全的,但有幾種實作線程安全的寫法。
1、餓漢模式:
因為執行個體被static和final修飾,在對象加載到記憶體的時候初始化,是以線程安全。
public class HungrySingleton {
private String name;
private static final HungrySingleton hungrySingleton = new HungrySingleton("張三");
public HungrySingleton(String name){
this.name = name;
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
雖然這樣寫線程安全,但他還是有缺陷的,在getBean執行個體之前,不能不給他設定屬性和參數,這時候懶漢模式就出現了,可以通過雙重檢索可以實作線程安全。
2、懶漢模式:
private String name;
private static LazySingleton lazySingleton;
public LazySingleton(String name) {
this.name = name;
}
public static LazySingleton getInstance() {
//第一次通路的時候沒有對象,是以擷取對象
if (lazySingleton == null) {
lazySingleton = new LazySingleton("張三");
}
return lazySingleton;
}
public static LazySingleton getInstance2() {
//保證線程安全
synchronized (lazySingleton) {
if (lazySingleton == null) {
lazySingleton = new LazySingleton("張三");
}
}
return lazySingleton;
}
public static LazySingleton getInstance3() {
//保證線程安全,性能提升
if (lazySingleton == null) {
synchronized (lazySingleton) {
if (lazySingleton == null) {
lazySingleton = new LazySingleton("張三");
}
}
}
return lazySingleton;
}
- getInstance()方法可以實作,第一次通路的時候沒有對象,是以為null的時候,擷取執行個體對象,但這種情況下多線程通路時候,會出現異常,導緻建立多個執行個體,如何解決呢?
- getInstance2()方法可以保證線程安全,上鎖之後,其他線程不可以進入,但這種情況會出現什麼問題呢?會一直上鎖,導緻沒必要的性能開銷,實際隻需要在第一次建立的上鎖。
- getInstance3()這就是為什麼要用雙重效驗,先判斷是否為null,然後在用synchronized上鎖實作線程安全。