【问题标题】:Thread-safety simple线程安全简单
【发布时间】:2014-11-02 12:06:22
【问题描述】:

如果我在多线程环境中有一个组件列表,并且如果我在这个列表上执行任何操作,除了 add(在这种情况下我在列表上使用关键字 synchronized)和 get(组件调用的方法是 thread-安全),那是线程安全的吗?

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
}

【问题讨论】:

  • 提供必要的代码来复制您的场景。根据当前的描述,代码仍然可能是线程不安全的。
  • Allawys 线程不安全? @LuiggiMendoza
  • useComponents 是线程不安全的。当您遍历myContainer 的内部元素时,任何其他线程都可以添加一个新的Component

标签: java multithreading


【解决方案1】:

在当前形式中,它不是线程安全的:useComponents 方法可以由一个线程执行。同时,另一个线程可以调用add,从而在迭代时修改集合。 (这种修改可能发生在 两次对 c.use() 的调用之间,因此 use() 方法是线程安全的这一事实对您没有帮助。

严格来说,这甚至不限于多线程:如果c.use() 内部调用test.add(someOtherComponent)(即使它是在同一个线程中完成的!)这将抛出一个ConcurrentModificiationException ,因为再次在迭代时修改了集合。

可以通过简单地将迭代包装到 synchronized 块中来实现线程安全(没有针对并发修改的安全性):

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>();

然后您甚至可以完全删除同步。但是您应该知道其中的含义:列表的内容将在每次修改期间复制(因此得名...)。这通常用于您有一个经常迭代但很少修改的小集合的情况。 (所有形式的听众都是一个典型的例子)。

【讨论】:

  • 我建议使用另一种具有不同并发结构的方法,例如由 LinkedBlockingQueue 支持的 BlockingQueue
  • @LuiggiMendoza 是的,docs.oracle.com/javase/7/docs/api/java/util/concurrent/… 包包含一些可以可能使用的集合。根据问题标题,我想指出主要问题,并展示最简单的替代方案(尽管它们可能不是每个应用案例的“最佳”替代方案)
  • 我知道,我的评论只是告诉您,您可以在当前帖子中添加另一个解决方案。
  • 我们在 Java 8 上,更接近于 Java 9。我建议你也使用最新的 javadoc :)
【解决方案2】:

看起来没问题,除了我不确定 useComponents() 中的迭代器行为是否会同时向列表中添加元素。

您是否考虑改用CopyOnWriteArrayList

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多