2013-05-28 68 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

相關問題