每次引用類別都只會產出相同的物件
適合用在: 執行緒池(thread pool),快取區(cache),對話盒、處理對話設定和登錄的物件,和驅動程式溝通的物件。
作法
假如有一個類別叫做MyClass,現在要讓MyClass變成獨體模式,讓外面的類別只能透過 MyClass.getInstance() 取得MyClass物件。
1 | public class MyClass { |
其他類別要取用MyClass
1 | public static void main(String args[]) { |
多執行緒下獨體模式會遇到的狀況
假如有兩個thread(thread 1和thread 2),同時要跟MyClass取得物件,但會面臨thread1和thread2會取得不同的MyClass物件,情況如下:
解法一:只要把getInstance()給同步化 (會有效能不佳的狀況,可能造成效率下降100倍)
1 | public class MyClass { |
但我們只需要第一次進入getInstance才進行同步化就好,不然其他次要取得uniqueInstnace都得變成同步的方式,造成取用Instance的緩慢
解法二:率先建立實體,不要等到有人呼叫getInstance才new出MyClass實體
1 | public class MyClass { |
此作法依賴JVM載入此類別時,馬上建立此唯一的獨體物件,JVM保證在任何執行緒存取uniqueInstnace靜態變數之前,一定先建立此實體
解法三:利用 “雙重檢查上鎖” 在getInstance()中減少使用同步化
利用雙重檢查上鎖,首先檢查是否實體已經建立了,
若沒有,“才”進行同步化,如此一來只有第一次進入getInstance才同步化,才是我們所想要的。
public class MyClass {
// volatile為Java 6之後才有的關鍵字,能夠使執行緒們取得相同的uniqueInstance
private volatile static MyClass uniqueInstance;
private MyClass() {}
public static MyClass getInstance() {
// 只有第一次才徹底執行以下程式碼
// 當執行緒遇到被宣告成volatile的uniqueInstnace,會變得謹慎
if(uniqueInstance == null) {
synchronized(MyClass.class) {
// 再檢查一次,若為null則new MyClass();
if(uniqueInstance == null) {
uniqueInstance = new MyClass();
}
}
}
return uniqueInstance;
}
}