第一種寫法:餓漢式
//餓漢式
public
class
singleobject1
public
static singleobject1 getinstance()
}
第二種寫法:懶漢式
1、迭代一:
//懶漢式: 在多執行緒環境下不安全,會產生多個例項!
public
class
singleobject2
public
static singleobject2 getinstance()
return instance;
}public
static
void
main
(string[
] args)).
start()
;});
}}
singleobject2()
...singleobject2()
...com.wzj.執行緒.單例模式.singleobject2@7ea6e10f
singleobject2()
...singleobject2()
...singleobject2()
...com.wzj.執行緒.單例模式.singleobject2@7fdaab5b
com.wzj.執行緒.單例模式.singleobject2@3bbb38b7
com.wzj.執行緒.單例模式.singleobject2@1dc727cc
com.wzj.執行緒.單例模式.singleobject2@7e611cce
分析:是什麼原因導致的呢?因為多執行緒是非同步執行的,在某個時間點多個執行緒可能會同時執行到**中的①處,然後繼續往下執行,可能就會導致該類產生多個例項。既然分析出了原因是因為某個時間點同時進來的多個執行緒導致,那麼我就加鎖讓他們乙個乙個同步進來。
2、迭代二:加鎖
public
static singleobject2 getinstance()
}return instance;
}
singleobject2()
...com.wzj.執行緒.單例模式.singleobject2@7ea6e10f
com.wzj.執行緒.單例模式.singleobject2@7ea6e10f
com.wzj.執行緒.單例模式.singleobject2@7ea6e10f
com.wzj.執行緒.單例模式.singleobject2@7ea6e10f
com.wzj.執行緒.單例模式.singleobject2@7ea6e10f
加完鎖之後,確實變成單例了。但是你有沒有發現每次呼叫該方法執行裡面的**的時候都加鎖,這會使得程式的執行效率降低。3、迭代三:使用雙重檢查機制
public
static singleobject2 getinstance()
}//②
}return instance;
}
分析:假設兩個執行緒t1,t2執行到了①處,假設t1執行緒先搶到cpu的執行權,然後獲取了鎖,這時t2是進不來的,等t1執行到了②處,假設t2執行緒搶到了cpu的執行權,這時它進去執行if判斷結果是不滿足條件,因為t1執行緒已經建立了該類的物件,然後t2也執行完了,這時其他執行緒進來直接執行③處,由於不為空所以直接返回例項了,要是不加③處的**,就每個執行緒進來都得搶鎖,然後在④處判斷,因為耗時而且沒必要,所以在③處加該判斷是很有必要的!4、迭代四:volatile
你天真的以為用了雙重檢查機制就完事了,小夥子還是太年輕。雙重檢查機制可能會出現空指標的問題。這是由於編譯器為了優化可能會幫你做的指令重排序!
private
static
volatile singleobject2 instance;
5、說清楚什麼情況下雙重檢查機制會導致空指標的問題!
我為什麼會問這個呢?因為不是我問的,哈哈哈,因為今天我在寫單例的時候,由於是多執行緒的訪問,我就將它寫成了這種雙重檢查+
volatile的形式,然後提交後,不料就被function leader給看到了,就連環炮來問我,問我這樣寫的好處,我就一一跟它說了,他笑著說沒見過加類鎖這種形式,說我寫的不規範,我:額,**不規範了,還說應該拿instance作為鎖,我說第一次進來instance不是空的嗎,怎麼可以作為鎖呢?這不是導致空指標嗎,他沉默了,然後他要問為什麼要加兩次判斷,這不是多餘嗎,我還是跟他解釋,他又沉默了。然後他又問為什麼要加volatile,我剛開始也不是特別清楚,我就和他說只知道是編譯器為了優化幫我們做了重排序,可能會導致空指標。所以我加上volatile關鍵字禁止重排序,這樣就可以避免這種情況的發生,然後他說這怎麼會空指標啊,就算重排序也沒問題啊,他理解的重排序是編寫**的時候互換位置,然後又說不要在網上看了一下就直接用,突顯你會新技術啊,這可是要投產的,所以你看你加這個volatile根本什麼用都沒有,寫的多餘,耗費效能,我:額,耗費個屁的效能。要說效能這專案中好多**得重構。當然這是我心裡想的,我表明就笑笑不說話,你是大哥,你愛咋樣咋樣!。
public
class
singleobject2
private
singleobject2()
public
static singleobject2 getinstance()
}}return instance;
}public
static
void
main
(string[
] args)).
start()
;});
}}
在①處其實 new singleobject2(),其實不是乙個原子性的操作,它可以分為三步1、分配記憶體空間
2、初始化物件
3、將物件指向剛分配的記憶體空間
但是有些編譯器為了效能的原因,可能會將第二步和第三步進行重排序,順序就成了:
1、分配記憶體空間
2、將物件指向剛分配的記憶體空間
3、初始化物件
//使用靜態內部類的方式
public
class
singleobject3
private
static
class
instanceholder
public
static singleobject3 getinstance()
}
最後:來自雖然帥,但是菜的cx//使用列舉來實現單例,很好,但是個人感覺不太優雅,可能是我太菜了!
public
class
singleobject4
private
enum singleton
public singleobject4 getinstance()
}public
static singleobject4 getinstance()
public
static
void
main
(string[
] args)}.
start()
);}}
多執行緒中的單例模式
第一種寫法 餓漢式 public class singleobject1 public static singleobject1 getinstance 第二種寫法 懶漢式 在多執行緒環境下不安全,會產生多個例項 public class singleobject2 public singleobj...
多執行緒 單例模式
單例模式 是非常典型常用的一種設計模式 乙份資源只能被申 載一次 單例模式的方法建立的類在當前程序中只有乙個例項 資源的程式初始化的時候就去載入,後面使用的時候直接使用,使用的時候比較流暢,有可能會載入用不上的資源,導致程式初始化時間比較慢。include class single instance...
單例模式多執行緒
單例模式 確保某個類只有乙個例項化物件 import time class a from threading import lock instance none lock lock def new cls,args,kwargs 加鎖確保時間片不發生輪轉 with cls.lock ifnot cl...