2013-07-08 46 views
1

即使我們使用同步方法並因此獲得對Helper對象的鎖,爲什麼此代碼不是線程安全的?即使使用同步方法,爲什麼此代碼不是線程安全的?

class ListHelper <E> { 
    public List<E> list = Collections.synchronizedList(new ArrayList<E>()); 

    public synchronized boolean putIfAbsent(E x) { 
     boolean absent = !list.contains(x); 
     if (absent) 
      list.add(x); 
     return absent; 
    } 
} 
+4

也許是......誰說它不是線程安全的?你是否遇到競爭條件或僵局? –

+0

這是Java併發實踐中的一個例子,無法理解爲什麼這個例子被認爲是不安全的。 – Ullas

+0

我有點驚訝,他們沒有解釋爲什麼... –

回答

11

因爲當contains返回時,列表被解鎖,然後在調用add時再次鎖定。其他的東西可以在兩者之間添加相同的元素。

如果您的意思是隻使用助手對象中的列表,應該聲明爲private;如果你這樣做,只要列表的所有操作都通過helper對象中同步的方法,代碼就會是線程安全的。同樣值得注意的是,只要是這種情況,您就不需要使用Collections.synchronizedList,因爲您在自己的代碼中提供了所有必要的同步。

或者,如果您希望允許列表爲公共​​,則需要在列表中同步您的訪問權限,而不是在輔助對象上。下面是線程安全的:

class ListHelper <E> { 
    public List<E> list = Collections.synchronizedList(new ArrayList<E>()); 

    public boolean putIfAbsent(E x) { 
     synchronized (list) { 
      boolean absent = !list.contains(x); 
      if (absent) 
       list.add(x); 
      return absent; 
     } 
    } 
} 

不同的是,它使用相同的鎖定爲列表的其他方法,而不是一個不同。

+0

準確地說,我同意。 –

+0

謝謝,根據JCP的解釋,它會失敗,因爲我們使用錯誤的鎖(即使用助手對象作爲鎖)。通過保持列表爲公共​​,並且如果我們使用同步塊使用列表作爲鎖調用contains方法,它會正常工作。我在閱讀時錯過了公共部分,謝謝指出。 – Ullas

3

此代碼不是線程安全的,因爲列表是公開的。

如果列表實例是私有的,並且在別處沒有引用,則此代碼是線程安全的。否則它不是線程安全的,因爲多個線程可能同時操縱列表。

如果列表未在別處引用,只要所有列表操作都通過同步方法進行並且對該列表的引用永遠不會返回任何內容,則無需通過collections類將其聲明爲同步列表。

當標記同步的方法,調用該方法的所有線程都與對象實例同步所述方法是定義。這就是爲什麼如果ListHelper內部列表實例未在其他地方引用,並且所有方法都是同步的,你的代碼會是線程安全的。

1

線程安全的一個主要組件不僅僅涉及互斥。完成對象狀態的原子更新是完全可能的,即實現狀態轉換,使對象保持有效狀態且其不變性保持不變,但如果仍然將對象的引用仍發佈爲不可信或不完整時,仍然會使對象容易受到攻擊調試客戶端。

在這個例子中你張貼:

public synchronized boolean putIfAbsent(E x) { 
    boolean absent = !list.contains(x); 
    if (absent) 
     list.add(x); 
    return absent; 
} 

的代碼是線程安全的,因爲W.M.指出。但我們無法保證x本身以及其他可能引用的代碼。如果這樣的引用確實存在,另一個線程可以修改列表中的相應元素,從而破壞您爲防止列表中對象的不變而做出的努力。

如果您從您不信任或不知道的客戶端代碼接受此列表的元素,一個好的做法是製作x的防禦副本,然後將其添加到您的列表中。同樣,如果您要將列表中的對象返回給其他客戶端代碼,請做出防禦性副本並返回,以確保您的列表保持線程安全。

此外,該列表應該完全封裝在類中。通過將其公開化,任何位置的客戶端代碼都可以自由訪問這些元素,並且無法保護列表中對象的狀態。

+0

好點。在考慮這類問題時,我傾向於假設所使用的對象是不可變的,但總是值得確保的是這種情況,或者已經採取措施來處理如果不是這樣的問題。 – Jules

相關問題