[英]Double Checked Locking in Singleton
這是我的單例模式自定義類。 在這段代碼中,我使用如下雙重檢查鎖定。 當我在某些來源上閱讀了許多帖子時,他們說雙重檢查很有用,因為它可以防止同時運行的兩個並發線程生成兩個不同的對象。
public class DoubleCheckLocking {
public static class SearchBox {
private static volatile SearchBox searchBox;
// private constructor
private SearchBox() {}
// static method to get instance
public static SearchBox getInstance() {
if (searchBox == null) { // first time lock
synchronized (SearchBox.class) {
if (searchBox == null) { // second time lock
searchBox = new SearchBox();
}
}
}
return searchBox;
}
}
我還是不太明白上面的代碼。 有什么問題,如果兩個線程在 instance 為 null 時一起運行同一行代碼?
if (searchBox == null) {
synchronized (SearchBox.class) {
if (searchBox == null) {
searchBox = new SearchBox();
}
}
}
當那個出現。 兩個線程都會看到對象為空。 然后兩者同步。 然后,他們再次檢查,仍然看到它 null 。 並創建兩個不同的對象。 哎呀。
請為我解釋。 我理解錯了什么?
謝謝 :)
不,由於您正在獲取對SearchBox.class
鎖定,因此一次只有一個線程會進入同步塊。 所以第一個線程進入然后發現searchBox
為空並創建它然后離開同步塊,然后第二個線程進入塊然后它發現searchBox
不為空,因為第一個線程已經創建了它所以它不會創建一個新的searchBox
實例。
雙重檢查模式用於避免每次執行代碼時都獲得鎖定。 如果調用沒有同時發生,那么第一個條件將失敗,代碼執行將不會執行鎖定,從而節省資源。
讓我們看看這段代碼:
1 if (searchBox == null) {
2 synchronized (SearchBox.class) {
3 if (searchBox == null) {
4 searchBox = new SearchBox();
5 }
6 }
讓我們試着推理一下。 假設我們有兩個線程A
和B
並假設其中至少一個到達第 3 行並觀察到searchBox == null
為true
。 由於synchronized
塊,兩個線程不能同時在第 3 行。 這是關鍵,理解為什么雙重檢查鎖定的工作方式。 因此,必須是A
或B
首先通過synchronized
。 不失一般性,假設該線程是A
。 然后,當看到searchBox == null
為真時,它會進入語句的主體,並將searchBox
設置為SearchBox
一個新實例。 然后它將最終退出synchronized
塊。 現在輪到B
進入:記住, B
被阻塞等待A
退出。 現在當它進入塊時,它會觀察searchBox
。 但是A
將只剩下將searchBox
設置為非null
值。 完畢。
順便說一下,在 Java 中,實現單例的最好方法是使用單元素enum
類型。 從有效的Java :
雖然這種方法尚未被廣泛采用,但單元素枚舉類型是實現單例的最佳方式。
僅當您擔心多個線程同時調用單例或一般情況下獲取鎖的成本時,才需要此雙重檢查鎖。
它的目的是防止不必要的同步,從而使您的代碼在多線程環境中保持快速。
如果您在 Java 1.5 或更高版本中運行,並且您在雙重檢查鎖定機制中使用volatile
關鍵字,它會正常工作。 當您使用volatile
關鍵字時,根據上面的相同鏈接,您的示例沒有被破壞。
if (searchBox == null) { //1
synchronized (SearchBox.class) {
if (searchBox == null) { //2
searchBox = new SearchBox();
}
}
}
}
所以基本上外部if
用於防止冗余鎖 - 它讓所有線程知道已經有一個對象並且他們不需要鎖定/做任何事情。 內部if
用於讓並發線程知道另一個線程是否已經創建了該對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.