2014-11-02 78 views
0

如果我有一個多線程環境中的組件列表,並且如果我在此列表上執行任何操作,除了添加(我在此例中使用列表中的同步關鍵字)並獲取(方法由a組件是線程安全的),線程安全嗎?線程安全簡單

public class Test { 

    private final ArrayList<Component> myContainer = new ArrayList<Component>(); 

    public void add(Component){ 
     synchronized(myContainer){ 
      myContainer.add(Component) 
     } 
    } 

    public void useComponents() 
    { 
     for(Component c : myContainer) 
      c.use(); // method thread-safe 
    } 

    // no other operations on myContainer 
} 
+1

提供必要的代碼以複製您的方案。在當前的描述中,代碼仍然可能是線程不安全的。 – 2014-11-02 12:08:05

+0

Allawys線程不安全? @LuiggiMendoza – kaoziun 2014-11-02 12:27:53

+0

'useComponents'是線程不安全的。任何其他線程可能在遍歷myContainer的內部元素時添加一個新的Component。 – 2014-11-02 12:29:01

回答

0

它看起來不錯,但我不知道在useComponents()如果你同時添加元素的列表迭代器行爲。

您是否考慮使用CopyOnWriteArrayList代替?

1

在當前形式中,它不是線程安全的:useComponents方法可以由一個線程執行。同時,另一個線程可能會調用add,因此在迭代期間修改集合。 (這種修改可能發生在之間兩次調用c.use(),所以事實上use()方法是線程安全的將不會幫助你在這裏)。

嚴格地說,這甚至不是侷限於多線程:如果c.use()內部調用test.add(someOtherComponent)(!即使是在同一個線程中完成的),這將拋出一個ConcurrentModificiationException,因爲再次,收集的同時被修改迭代。

線程安全(無安全agains併發修改)可以通過簡單地包裹迭代到​​塊來實現:

public void useComponents() 
{ 
    synchronized (myContainer) 
    { 
     for(Component c : myContainer) 
      c.use(); // method thread-safe 
    } 

}

然而,這仍然會出現ConcurrentModificationException的可能性。最有可能的是c.use()調用不會(也不應該)修改該組件所在的集合(否則,可以對通常的設計提出質疑)。

如果你想允許c.use()呼籲修改集合,你可以用CopyOnWriteArrayList替換集合:

private final List<Component> myContainer = 
    new CopyOnWriteArrayList<Component>(); 

,然後你甚至可以完全刪除synchroniziation。但是您應該瞭解其含義:在每次修改期間,列表的內容將爲複製(因此名稱...)。這通常用於您經常迭代但很少修改的小集合的情況。 (所有形式的聽衆都是典型的例子)。

+0

我建議使用另一種方法,使用不同的併發結構,如'LinkedBlockingQueue'備份的'BlockingQueue'。 – 2014-11-02 12:36:33

+0

@LuiggiMendoza是的,http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html包中包含一些可能*可能被用來代替的集合。基於問題標題,我想指出主要問題,並展示最簡單的替代方案(儘管它們可能不是每個應用案例的「最佳」方案) – Marco13 2014-11-02 12:39:29

+0

我知道,我的評論只是爲了告訴你,你可能會爲您的當前帖子添加另一個解 – 2014-11-02 12:41:21