-1

下面給出所示的輸出:在對象引用或值上Java「同步」塊鎖定嗎?

Path path1 = Paths.get("/Users/someone/foo"); 
    Path path2 = Paths.get("/Users/someone/foo"); 
    System.out.println(path1.toString() == path2.toString()); // outputs false 
    System.out.println(path1.toString().equals(path2.toString())); // outputs true 

鑑於以下兩個線程,有可能是兩個線程在臨界段在同一時間運行?

// Thread 1 
    synchronized (path1.toString()) { 
     // Critical section 
    } 

    // Thread 2 
    synchronized (path2.toString()) { 
     // Critical section 
    } 
+0

每個對象都有自己的監視器;這是由同步塊獲取的內容。因此,只有'path1.toString()== path2.toString()'纔會互相排斥。 –

+1

通常,對方法調用的結果進行同步並不是一個好主意:即使您在兩個線程中僅同步到'path1.toString()',也可能根本不會互斥,如果它始終返回新的對象(你不知道是否是這種情況,它可以任意改變)。 –

+0

而你當然不能指望那些引用是相同的。他們很可能不會。無論如何,你爲什麼要鎖定一個'String'? 'String'帶有大量的貨運和語義,僅僅用作鎖對象。你只需要一個「對象」。 –

回答

1

正如Java Language Specification, section 14.19(JLS)形成文件,對象上​​聲明鎖。如果您將「value」作爲字符串值(如path1.toString().equals(path2.toString())),則回答爲「否」—您的代碼幾乎肯定不是線程安全的。在JLS的說法,如果表達式的類型是引用類型(根據需要用於​​語句),則值表達的要麼null或對象。發佈代碼中的兩個塊不互相排斥,除非兩個toString()調用返回相同的對象引用(path1.toString() == path2.toString())。

+0

這與引用的參考文獻告訴我們的情況相反。它說:「否則,讓表達式的非空值爲V.正在執行的線程鎖定與V相關的監視器。」它會鎖定與該表達式相關聯的監視器,而不是該引用的引用。此外,如§17.1所述,監視器與對象關聯,而不是參照。 「Java中的每個對象都與一個監視器關聯,一個線程可以鎖定或解鎖。」 –

+0

@LewBloch再次,這是一個沒有區別的區別。這是一個參考價值的表達。 – EJP

+0

說出JLS的相反確實有所作爲,特別是當它解決OP所問的確切問題並給出相反的答案時。不僅如此,在你看到對象和引用(指針)引起的混淆有多大的損害之前,你只需要閱讀這個論壇幾分鐘。它在鎖定,GC,多態性,複製和克隆,不變性,參數傳遞(以及它是否是有價值的)方面都非常重要 - 真正的一切。因此,你聲稱它是「沒有區別的區別」,與其試圖捍衛的答案相反。 –

6

參考的值。這是一個沒有區別的區別。 toString()是一個參考。它不會與任何其他toString()值相同,除非兩者都已被實施,或者它們都源自相同或相同的字符串文字。

+1

我想OP是想知道如果兩個字符串相等(使用'equals()')是否足以確保線程安全。 –

+0

@TedHopp我沒有看到任何關於他可能會或可能不會意味着什麼的猜測。我正在回答他問的問題。 – EJP

+0

是的Ted,我想知道在synchronized()關鍵字中判斷兩個對象是否相等時是否使用了equals()或者== ==。 – albusshin