2012-05-13 41 views
3

那天我問了a similar question,但對回覆不滿意,主要是因爲我提供的代碼有一些人們關注的問題。對象鎖定私有類成員 - 最佳實踐? (Java)

基本上,在Java中鎖定私有成員的最佳做法是什麼?假設每個私有字段只能被孤立地操作,而不能一起操作(如下面的測試類示例),應該直接鎖定每個私有字段(示例1),還是應該爲每個要鎖定的私有字段使用一個普通鎖對象(例2)?

實施例1:鎖定私有字段直接

class Test { 
    private final List<Object> xList = new ArrayList<Object>(); 
    private final List<Object> yList = new ArrayList<Object>(); 

    /* xList methods */ 

    public void addToX(Object o) { 
    synchronized(xList) { 
     xList.add(o); 
    } 
    } 

    public void removeFromX(Object o) { 
    synchronized(xList) { 
     xList.remove(o); 
    } 
    } 

    /* yList methods */ 

    public void addToY(Object o) { 
    synchronized(yList) { 
     yList.add(o); 
    } 
    } 

    public void removeFromY(Object o) { 
    synchronized(yList) { 
     yList.remove(o); 
    } 
    } 
} 

實施例2:每私有字段

class Test { 
    private final Object xLock = new Object(); 
    private final Object yLock = new Object(); 
    private List<Object> xList = new ArrayList<Object>(); 
    private List<Object> yList = new ArrayList<Object>(); 

    /* xList methods */ 

    public void addToX(Object o) { 
    synchronized(xLock) { 
     xList.add(o); 
    } 
    } 

    public void removeFromX(Object o) { 
    synchronized(xLock) { 
     xList.remove(o); 
    } 
    } 

    /* yList methods */ 

    public void addToY(Object o) { 
    synchronized(yLock) { 
     yList.add(o); 
    } 
    } 

    public void removeFromY(Object o) { 
    synchronized(yLock) { 
     yList.remove(o); 
    } 
    } 
} 

回答

9

個人而言,我傾向於第二種形式。沒有其他代碼在所有可以使用該參考(禁止反射,調試API等)。您不必擔心列表的內部細節是否嘗試同步它。 (你在列表上調用的任何方法顯然都可以訪問this,所以可以同步。)你純粹使用將它用於鎖定 - 所以你也在「我是鎖」和「 「我是一個名單」。

我覺得這樣可以更容易推理顯示器,因爲您可以很容易地看到全部使用它的可能代碼。

您可能希望創建一個純粹用作監視器的獨立類,並且可覆蓋toString(),這可以幫助進行診斷。它也會使變量的目的更加清晰。

誠然,這種方法確實採取更多的內存,並且通常你不需要擔心代碼鎖定在this ...但我個人覺得分離關切,並不必擔心的好處是否代碼確實對鎖定超過了效率成本。如果你發現「浪費」的對象是某種原因的性能瓶頸(並且在分析了可能要同步的類中的代碼之後),則可以始終選擇第一種形式。

(我個人希望Java和。NET 還沒有下去了「每個對象都有一個關聯的顯示器」的路線,但這是一個不同的日子的咆哮)。

0

讓我們這樣說吧:第二種方法使用更多的代碼 - 這是什麼額外的代碼買你?就併發性而言,兩者完全相同,所以它必須是來自應用程序設計大局的其他方面。

0

即使您確定您正在執行鎖定的對象永遠不會更改,我發現使用特殊對象僅用於鎖定更令人放心。它使它更透明。如果將來其他人將該課程顯着擴展和/或修改,他可能會發現一個理由,使其不會被終止,而不會注意到它被用於鎖定。這可能會很快導致問題。線程安全並不是微不足道的,並且在代碼演變時可能變得更加複雜,因此儘可能使其儘可能清晰和安全。與線程安全問題的診斷成本相比,爲鎖定設置單獨對象的成本較小。

+0

同樣,有人可以對類進行修改,使兩個對象被鎖定在一起使用,而不會注意到鎖。修改要求從這一點開始使用一個鎖,但是某人不會注意到它。我說我不認爲這是一個很好的藉口。你所說的風險最小化是非常重要的,但是如果你並沒有意識到併發性方面的問題,併發代碼或多或少地保證會遇到麻煩。 –