【问题标题】:Java Synchronized listJava 同步列表
【发布时间】:2012-07-06 19:20:53
【问题描述】:

我有一个预先填充的数组列表。而且我有多个线程将从数组列表中删除元素。每个线程调用下面的 remove 方法并从列表中删除一项。以下代码是否给了我一致的行为?

ArrayList<String> list = Collections.synchronizedList(new ArrayList<String>());

void remove(String item)
{
     do something; (doesn't work on the list)
     list.remove(item);
}

谢谢!

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    只要您不要求“删除”方法是原子的,那应该没问题。

    换句话说,例如,如果“做某事”检查该项目在列表中出现多次,那么当您到达下一行时,该检查的结果可能会出错。

    另外,请确保在迭代时同步列表:

    synchronized(list) {
        for (Object o : list) {}
    }
    

    正如 Peter Lawrey 所提到的,CopyOnWriteArrayList 可以让您的生活更轻松,并且可以在高度并发的环境中提供更好的性能。

    【讨论】:

      【解决方案2】:

      是的,如果您还对列表进行迭代,请小心,因为在这种情况下,您需要对其进行同步。来自Javadoc

      用户在迭代返回的列表时必须手动同步它:

      List list = Collections.synchronizedList(new ArrayList());
          ...
      synchronized (list) {
          Iterator i = list.iterator(); // Must be in synchronized block
          while (i.hasNext())
              foo(i.next());
      }
      

      或者,您可以使用CopyOnWriteArrayList,它的写入速度较慢,但​​没有此问题。

      【讨论】:

      • 我有一个关于线程安全的问题here 所以想看看你能不能帮帮我?
      • CopyOnWriteArrayList 的重要提示。谢谢!
      • 当您需要同步列表时。您很可能需要排队。而是在 java 中使用阻塞队列。
      【解决方案3】:

      来自Collections#synchronizedList(List)javadoc

      返回由指定支持的同步(线程安全)列表 列表。为了保证串行访问,至关重要的是 所有访问后备列表已完成 通过返回的列表......当迭代它时,用户必须在返回的列表上手动同步。不遵循此建议可能会导致不确定的行为。

      【讨论】:

        【解决方案4】:

        它将为添加/删除操作提供一致的行为。但是在迭代时,您必须显式同步。 Refer this link

        【讨论】:

          【解决方案5】:

          是的,它可以正常工作,因为您有 synchronized list 。我建议你使用CopyOnWriteArrayList

          CopyOnWriteArrayList<String> cpList=new CopyOnWriteArrayList<String>(new ArrayList<String>());
          
              void remove(String item)
              {
                   do something; (doesn't work on the list)
                           cpList..remove(item);
              }
          

          【讨论】:

            【解决方案6】:

            列表可能有 2 个不同的问题:
            1) 如果即使在单线程环境中在迭代中进行修改,也会出现 ConcurrentModificationException,如下例所示:

            List<String> list = new ArrayList<String>();
            for (int i=0;i<5;i++)
               list.add("Hello "+i);
            
            for(String msg:list)
               list.remove(msg);
            

            所以,为了避免这个问题,你可以这样做:

            for(int i=list.size()-1;i>=0;i--)
               list.remove(i);
            

            2)第二个问题可能是多线程环境。如上所述,您可以使用 synchronized(list) 来避免异常。

            【讨论】:

              【解决方案7】:
              synchronized(list) {
                  for (Object o : list) {}
              }
              

              【讨论】:

              • 总是尝试在你的答案中添加一些相关的描述。
              • 您能否扩展您的答案以包括对您的代码的解释?它对读者的帮助超出您的想象。
              • 请详细说明您的答案
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-02-19
              • 2010-11-18
              • 2011-11-12
              • 2022-11-19
              相关资源
              最近更新 更多