2013-02-06 73 views
4

任何人都可以解釋這些示例之間有什麼區別嗎?我應該使用什麼作爲Java中同步語句的鎖對象

實施例#1

public class Main { 

    private Object lock = new Object(); 
    private MyClass myClass = new MyClass(); 

    public void testMethod() { 
     // TODO Auto-generated method stub 
     synchronized (myClass) { 
      // TODO: modify myClass variable 
     } 
    } 

} 

實施例#2

package com.test; 

public class Main { 

    private MyClass myClass = new MyClass(); 
    private Object lock = new Object(); 

    public void testMethod() { 
     // TODO Auto-generated method stub 

     synchronized (lock) { 
      // TODO: modify myClass variable 
     } 
    } 

} 

我應該作爲監測鎖使用,如果我需要採取有關同步護理修改變量時?

回答

2

假設Main不打算成爲「泄漏抽象」,這裏第一個和第二個示例之間的差異很小。

使用Object而不是其他類可能更好,因爲Object實例沒有字段,因此較小。而Object -as-lock成語則明確表示lock變量僅用於鎖定。

話雖如此,鎖定一個沒有別的東西會看到的對象是有一定的優勢的。在Main(例如this)上同步的Main方法的問題在於其他不相關的代碼也可能爲了不相關的目的而在其上同步。通過在專用(私人)鎖定對象上進行同步,可以避免這種可能性。


在迴應評論:

有這兩種情況有很大的差異。在第一個你鎖定你想要操作的對象。在第二個中,你鎖定了一些與被操作對象沒有明顯關係的其他對象。第二種情況需要更多空間,因爲您必須分配(否則未使用的)對象,而不是使用您保護的已有實例。

我認爲你做了一個不正確的假設 - MyClass是需要保護的數據結構。事實上,這個問題並沒有這麼說。事實上,寫這個例子的方式意味着這個鎖旨在保護整個類別......不僅僅是其狀態的一部分。在這方面,有明顯的聯繫......

它會更好地鎖住MyClass是,如果Main是漏水的抽象,允許其他代碼來獲得其myClass參考保持的唯一情況。這將是糟糕的設計,尤其是在多線程應用程序中。

根據修訂歷史記錄,我很確定這不是OP的意圖。

+0

謝謝。確實,第二個例子在你的解釋之後開始變得更有意義。 –

+1

這兩種情況有很大的不同。在第一個你鎖定你想要操作的對象。在第二個中,你鎖定了一些與被操作對象沒有明顯關係的其他對象。第二種情況需要更多空間,因爲您必須分配(否則未使用的)對象,而不是使用您保護的已有實例。 –

2

在第一種情況下,您鎖定的對象只在該方法中知道,因此其他人不太可能使用同一個對象來鎖定,所以這樣的鎖幾乎是無用的。第二個變體對我來說更有意義。

同時,myClass變量也只有在這個方法中是已知的,所以其他線程不太可能訪問它,所以可能根本不需要鎖。需要更完整的例子來說更多。

+0

當然,我應該把'myClass'放在方法之外。我剛剛編輯了我的問題。 –

1

的差異是該類的鎖,其範圍 的 - 兩個主題是幾乎正交的同步

  • 對象具有不同的類可具有不同尺寸

  • 在不同的範圍的對象可以可在不同的環境中使用

基本上,兩者在行爲方面的表現相同同步

+3

你似乎沒有真正說出任何話。 –

+0

這是因爲沒有好的答案......它取決於具體的用例:他需要的數據鎖和他需要的數據範圍......同步的部分並不真正相關 –

0

這兩個例子都不是很好的syncronisation實踐。 lock Object應作爲私人字段放在MyClass中。

+0

我做了不要重視'鎖'應該是私人領域的事實。我剛剛編輯了這個問題。 –

3

當更改對象的變量時,語句同步很有用。

您正在更改myClass的變量,因此您要鎖定myClass對象。如果您要更改lock中的某些內容,則您需要鎖定lock對象。

在示例#2中,您正在修改myClass,但鎖定了lock對象,這是無稽之談。

+2

鎖定「鎖定」並修改「myClass」沒有問題。如果代碼'myClass'中的某個其他部分沒有獲取「鎖定」或使用其他機制來防止同時發生更改,則可能會出現問題。例#2在很多情況下都有意義。 –

+0

@Amit我在哪裏說鎖定'lock'和修改'myClass'有問題?我沒有。當#2合理時,你能向我展示一個例子嗎? – drzymala

+0

我檢查了原始問題中的編輯...例2#從您發佈答案的時間改爲我發表該評論的時間...我可以向您展示很多情況,其中當前示例#2是合理......但我認爲你的意思是舊的不合理@martini –

1

通常,您想要鎖定正在操作的數據的「根」對象。如果你想從對象A的字段中減去一個值並將該值添加到對象B中,則需要鎖定A和B之間某種常見(至少按慣例)的對象,可能是「所有者「這兩個對象。這是因爲你正在執行鎖定以維持單獨數據片段之間的「一致性」 - 鎖定的對象必須是共同的,並且在概念上必須包含必須保持一致的整個數據集。

當然,簡單的情況是,當您修改同一對象中的字段A和字段B時,在這種情況下鎖定該對象是明顯的選擇。

不太明顯的是,當你處理屬於一個類的靜態數據時。在這種情況下,你通常想要鎖定課程。

Java中很少需要一個單獨的「監視器」對象 - 僅用作可鎖定實體 - 但可能適用於兩個並行數組的元素,您希望在元素N之間保持一致性的兩個陣列。在這種情況下,像第三組監視器對象可能是合適的。 (注意,這在佈置一些規則時只是一個「快速入侵」),人們可以遇到很多微妙之處,尤其是當試圖允許最大限度地併發訪問大量訪問的數據時,在高性能計算之外的情況很少見)。

無論您選擇什麼,重要的是在所有對受保護數據的引用中選擇一致的。在引用/修改相同數據時,您不希望在一種情況下鎖定對象A,而在另一種情況下鎖定對象B. (並且請不要陷入認爲可以鎖定A類的任意實例並以某種方式鎖定A類的另一個實例的陷阱。這是一個經典的初學者的錯誤。)

在你上面的例子中,你通常想要鎖定創建的對象,假設你保證的一致性都是該對象的內部。但請注意,在這個特定的例子中,除非MyClass的構造函數以某種方式讓對象地址爲「轉義」,否則根本不需要鎖定,因爲另一個線程無法獲取新對象的地址。

+0

>請不要陷入這樣的想法:你可以鎖定一個任意的A類實例,並以某種方式鎖定另一個A類實例。這是一個經典的初學者的錯誤。 在我明白之前,我犯了幾次錯誤。 –

相關問題