簡體   English   中英

為什么Netbeans抱怨同步呼叫被條件包裹?

[英]Why does Netbeans complain about a synchronized call being wrapped with a conditional?

說我有一些這樣的代碼:

private static Thing t = null;
private static final Object lock = new Object();   

public static void foo() {
    if(t == null) { //Netbeans warning on this line.
        synchronized(lock) {
            if(t == null) {
                t = new Thing();
            }
        }
    }
    ...Do stuff with t...
}

現在,foo托管在服務器上,並且可能被許多用戶同時調用。 函數foo的目的是初始化t(如果尚未初始化的話),否則,使用初始化后的實例執行需要完成的所有工作。

但是,Netbeans給我這樣的代碼警告:

Remove the outer conditional statement

使用工具提示:

Double-checked locking

雙重檢查鎖定的目的是避免瓶頸等待人們釋放鎖定。 如果唯一的要檢查t是否為null的檢查是在同步塊內部,則每個人都必須等待他們的機會來查看t是否為null,並且所有人1都將有效地什么也沒有等待(因為t不會為null)。 。 因此,外部條件。

借助它,可以說是有奇跡的,有5個人同時將t == null解析為true。 一個用戶將獲得同步鎖,看到t == null仍然為true,然后對其進行初始化。 然后,該用戶將釋放該鎖,下一個用戶將對其進行鎖定,並幾乎立即將其釋放(因為t!= null不再存在),此操作將持續到5個用戶通過該鎖為止。 一直以來,其他連接的用戶跳過同步鎖,因為第一個用戶使t!= null。

那么,為什么Netbeans抱怨呢? 這似乎是完成AFAIK的最佳方法。

思考?

之所以抱怨,是因為按照書面規定,這是不安全的-至少可能是這樣。

因為t不是volatile ,所以Thing還在構造時,讀者線程就有可能讀取t的新值。 那將是一個不好的舉動-使用部分構造的對象是可怕的。

在Java 5推出新的內存模型之前,它甚至還不是線程安全的,並且字段標記為volatile 使用新的內存模型在某些情況下是安全的,甚至在沒有volatile情況下也可能是安全的,但是我個人還是會避免使用它:

  • 在大多數應用程序中,僅在每個呼叫中​​進行同步就不會成為很大的瓶頸
  • 通常作為靜態初始化程序的一部分進行初始化就足夠了:

     private static Thing t = new Thing(); 
  • 對於其他情況,還有嵌套類的其他技巧,它們仍然使用靜態初始化程序的惰性,但是即使訪問了其他成員,所有這些單一屬性也很懶惰。

  • 對於單身模式,請考慮使用枚舉代替。

有關DCL的老破碎了很多的更多信息,請閱讀“雙檢鎖壞了”宣言 (有關JDK 5的當前情況,請參閱結尾部分-但請考慮您是否真的希望代碼的維護者考慮所有這些問題。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM