單例模式-設計模式
阿新 • • 發佈:2021-01-11
技術標籤:設計模式
動機
- 在軟體系統中,經常有這樣一些特殊的類,必須保證它們在系統中只存在一個例項,才能確保它們的邏輯正確性、以及良好的效率。
- 如何繞過常規的構造器,提供一種機制來保證一個類只要一個例項?
- 這應該是類設計者的責任,而不是使用者的責任。
模式定義
保證一個類僅有一個例項,並提供一個該例項的全域性訪問點。
類圖
總結
- Singleton模式中的例項構造器可以設定為protected已允許子類派生。
- Singleton模式一般不要支援拷貝建構函式和Clone介面,因為這有可能導致多個物件例項,與Singleton模式的初衷違背。
- 如何實現多執行緒環境下安全的Singleton?注意對雙檢查鎖的正確實現。
例項
注意點
- 單例模式需要把建構函式設定為虛擬函式
- 需要考慮多執行緒的問題
- 使用雙檢查鎖機制
- 防止指令重排,java中使用volatile關鍵字
- 單列類
public class HouseSingleton {
// 新增volatile是為了避免指令重排
private static volatile HouseSingleton houseSingleton = null;
private HouseSingleton() {
System.out.println("Create HouseSingleton");
}
public static HouseSingleton getInstance() {
// 雙檢查鎖機制,可以保證只有例項每建立的時候鎖一次,其他情況下都不會鎖執行緒,不會導致效能下降。
// 問題是,可能出現指令重排,先分配記憶體然後直接把記憶體地址賦值給引用變數,導致還沒執行建構函式;
// 因此部分執行緒不能正常使用例項,因此需要藉助volatile關鍵字避免指令重排。
if (houseSingleton == null) {
synchronized (HouseSingleton.class) {
if (houseSingleton == null) {
houseSingleton = new HouseSingleton();
return houseSingleton;
}
}
}
return houseSingleton;
}
public void say() {
System.out.println("Say hello, name:" + Thread.currentThread().getName());
}
}
- 多執行緒呼叫單例類
public class Client {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(() -> {
HouseSingleton houseSingleton = HouseSingleton.getInstance();
houseSingleton.say();
}, "thread" + (i + 1));
thread.start();
}
Thread.sleep(10000);
}
}
// 執行結果
Create HouseSingleton
Say hello, name:thread1
Say hello, name:thread2
Say hello, name:thread3
Say hello, name:thread4
Say hello, name:thread86
Say hello, name:thread6
Say hello, name:thread7
Say hello, name:thread8
Say hello, name:thread9
Say hello, name:thread10
Say hello, name:thread11
Say hello, name:thread12
Say hello, name:thread13
Say hello, name:thread14
Say hello, name:thread15
Say hello, name:thread16
Say hello, name:thread18
Say hello, name:thread17
Say hello, name:thread19
Say hello, name:thread20
Say hello, name:thread21
Say hello, name:thread22
Say hello, name:thread23
Say hello, name:thread24
Say hello, name:thread25
Say hello, name:thread26
Say hello, name:thread27
Say hello, name:thread28
Say hello, name:thread29
Say hello, name:thread30
Say hello, name:thread31
Say hello, name:thread32
Say hello, name:thread33
Say hello, name:thread34
Say hello, name:thread35
Say hello, name:thread36
Say hello, name:thread38
Say hello, name:thread39
Say hello, name:thread40
Say hello, name:thread41
Say hello, name:thread42
Say hello, name:thread43
Say hello, name:thread44
Say hello, name:thread99
Say hello, name:thread97
Say hello, name:thread95
Say hello, name:thread100
Say hello, name:thread92
Say hello, name:thread91
Say hello, name:thread37
Say hello, name:thread90
Say hello, name:thread85
Say hello, name:thread84
Say hello, name:thread83
Say hello, name:thread81
Say hello, name:thread79
Say hello, name:thread77
Say hello, name:thread87
Say hello, name:thread76
Say hello, name:thread78
Say hello, name:thread89
Say hello, name:thread74
Say hello, name:thread73
Say hello, name:thread67
Say hello, name:thread65
Say hello, name:thread94
Say hello, name:thread96
Say hello, name:thread64
Say hello, name:thread63
Say hello, name:thread98
Say hello, name:thread62
Say hello, name:thread61
Say hello, name:thread66
Say hello, name:thread60
Say hello, name:thread58
Say hello, name:thread68
Say hello, name:thread56
Say hello, name:thread55
Say hello, name:thread54
Say hello, name:thread52
Say hello, name:thread69
Say hello, name:thread70
Say hello, name:thread71
Say hello, name:thread72
Say hello, name:thread75
Say hello, name:thread80
Say hello, name:thread82
Say hello, name:thread5
Say hello, name:thread88
Say hello, name:thread46
Say hello, name:thread50
Say hello, name:thread45
Say hello, name:thread93
Say hello, name:thread49
Say hello, name:thread48
Say hello, name:thread47
Say hello, name:thread51
Say hello, name:thread53
Say hello, name:thread57
Say hello, name:thread59