2014-11-02 159 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