2013-05-28 43 views
3

情况1:这不会导致ConcurrentModificationException?谁能告诉我为什么这不会导致ConcurrentModificationException。任何人都可以通过ConcurrentModificationException解释我吗?

public class UpdatePeople { 
    List <People> records = new ArrayList <People>(); 

    public class AsyncTask extends AsyncTask < Void, Void, Boolean > { 
     List <People> people; 

     public AsyncTask(List <People> allergy) { 
      this.people = people; 
     }@ 
     Override 
     protected Boolean doInBackground(Void...params) { 
      List <String> responses = new ArrayList <String>(); 
      for (People peopleList: this.people) { 

      } 

     } 

    } 
} 

案例2:这会导致ConcurrentModificationException因为我试图访问的人在我AsyncThread这不是线程安全的列表。我可以让我的人员列表实现CopyOnWriteArrayList这是线程安全的,这应该工作。

public class UpdatePeople { 
     List <People> records = new ArrayList <People>(); 

     public class AsyncTask extends AsyncTask < Void, Void, Boolean > { 
      @ 
      Override 
      protected Boolean doInBackground(Void...params) { 
       List <String> responses = new ArrayList <String>(); 
       for (People peopleList: records) { 

       } 

      } 

     } 
    } 
  1. 任何人都可以解释我什么是case 1恰好发生。我无法理解这是如何解决ConcurrentModificationException问题的。
  2. 是否将案例2从ArrayList更改为CopyOnWriteArrayList推荐?

添加异常:

05-28 20:34:21.073:E/XXX(904):未捕获的例外情况是:05-28 20:34:21.073:E/XXX(904):了java.lang.RuntimeException:一个错误而执行doInBackground发生 ()05-28 20:34:21.073:E/XXX(904):在 android.os.AsyncTask $ 3.done(AsyncTask.java :299)05-28 20:34:21.073: E/XXX(904):at java.util.concurrent.FutureTask $ Sync.innerSetException(FutureTask.java:273) 05-28 20:34:2 1.073:E/XXX(904):at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 05-28 20:34:21.073:E/XXX(904):at java.util。 concurrent.FutureTask $ Sync.innerRun(FutureTask.java:307) 05-28 20:34:21.073:E/XXX(904):在 java.util.concurrent.FutureTask.run(FutureTask.java:137)05 -28 20:34:21.073:E/XXX(904):在 android.os.AsyncTask $ $ SerialExecutor 1.run(AsyncTask.java:230)05-28 20:34:21.073:E/XXX(904 ): java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 05-28 20:34:21.073:E/XXX(904):at java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:569) 05-28 20:34:21.073:E/XXX(904):在 java.lang.Thread.run(Thread.java:856)05-28 20:34:21.073:E/XXX(904): 引起:JAVA .util.ConcurrentModificationException 05-28 20:34:21.073:E/XXX(904):在 的java.util.ArrayList $ ArrayListIterator.next(ArrayList.java:569)

+0

请加异常的消息,那就是“为(人民peopleList:记录)”中的代码回路你的问题 – mschenk74

+0

@ mschenk74:在我收到第二种情况下,exeception是环路for(People peopleList:records) – theJava

+0

当你有一个迭代器的时候,你已经掌握了修改对象的权利。 –

回答

6

一般而言,ConcurrentModificationException被抬起时,如果尝试修改集合在遍历它。例如:

public class Main { 

    public static void main(String[] args) 
    throws Exception { 

     final List<Object> c1 = new ArrayList<Object>(Arrays.<Object>asList(1, 2, 3)); 
     for (Object o: c1) c1.remove(o); 
    } 
} 

将导致java.util.ConcurrentModificationException在运行时,因为我们正在修改的列表,同时遍历它(注:这里只涉及单个线程)。这是通过列表的迭代检测,导致异常。

如果所需修改是从迭代器刚收到非常元素的缺失,可以通过与iterator directly工作达到预期的效果(在单线程情况!)。将for(每个)循环替换为:

final Iterator<Object> iterator = c1.iterator(); 

while (iterator.hasNext()) { 

    final Object o = iterator.next(); 
    if (satisfiesSomeCriterion(o)) iterator.remove(); 
} 

但是,这并不适用于所有修改。例如,添加不起作用。下面的代码确实还失败:

for (Object o: c1) c1.add(Integer.valueOf(((Integer)o).intValue() + 10)); 

如果底层的集合是一个List,您可以通过使用ListIterator,而不是一个简单的迭代器来解决这一限制:

final ListIterator<Integer> iterator = c1.listIterator(); 

while (iterator.hasNext()) { 

    final Integer o = iterator.next(); 
    if (satisfiesSomeCriterion(o)) iterator.add(Integer.valueOf(o.intValue() + 10); 
} 

但要注意,这不等同于上面给出的代码(被插入的元素的其他位置)。另请注意,ListIterator.add是一种可选方法;当一个实现被调用时可能会抛出一个UnsupportedOperationException

上述所有内容仅适用于单线程案例。如果尝试在没有正确同步的情况下同时从多个线程访问相同的集合,则会出现一组全新的问题,因为这不仅会在迭代线程中导致ConcurrentModificationException s,而且还会破坏集合内部的完整性数据结构。

有几件事情可以做:

  • 使用并发感知集合(如CopyOnWriteArrayList你已经提到)
  • 裹收集通过Collections.synchronizedList...Set...Whatever)。但请注意,在这种情况下,您仍负责为迭代提供适当的锁定规则。详情请参阅this answer
  • 使原始集合的副本将它传递给后台作业之前(并确保,即后台作业是使用该副本的唯一线程)
  • 通过​​块保护收集的所有用途(例如,使用集合本身作为“监视器”对象,但更好:使用专用监视器对象)。
+0

请确切地说,它仍然可以修改集合,同时用itr.remove(),itr.add() –

+0

真的很好+1来迭代它。 – Blackbelt

相关问题