2013-05-28 4 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 : 내가 스레드로부터 안전하지 않습니다 내 AsyncThread에있는 사람들의 목록에 액세스하려고 이것은 ConcurrentModificationException됩니다. 사람들 목록에 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) : 예외 uncaught이다 : 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) : 에서 java.util.concurrent.FutureTask $ Sync.innerSetException (FutureTask.java:273) 05-28 20 : 34 : 2 1.073 : E/XXX (904) : java.util.concurrent.FutureTask.setException (FutureTask.java:124) 05-28 20 : 34 : 21.073 : E/XXX (904) : java.util. 동시. 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) : 에서 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

질문에 "(people peopleList : records) for"루프 내부에있는 예외 및 코드 메시지를 추가하십시오. – mschenk74

+0

@ mschenk74 : 내가 얻은 두 번째 사례의 예외가 루프에 있습니다. for (People peopleList : records) – theJava

+0

오브젝트 위에 iterator가있는 동안 오브젝트를 수정하기 위해 손을 쳤습니다. –

답변

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의 원인이됩니다 (NB : 여기에 포함 된 단일 스레드). 이것은리스트의 반복자에 의해 검출되어 예외를 발생시킵니다.

반복자에서 방금받은 요소의 삭제가 원하는 수정 인 경우 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을 발생시킬 수있을뿐만 아니라 컬렉션 내부의 무결성을 파괴 할 수 있기 때문에 발생합니다 데이터 구조.

  • 가 (예 : CopyOnWriteArrayList 이미 언급 한 바와 같이) 동시성 인식 컬렉션을 사용
  • 랩 컬렉션 Collections.synchronizedList (...Set, ...Whatever)를 통해 :

    당신이 할 수있는 몇 가지가 있습니다. 하지만이 경우에는 반복과 관련하여 적절한 잠금 규정을 제공 할 책임이 있습니다. 자세한 내용은 this answer을 참조하십시오.

  • 백그라운드 작업에 전달하기 전에 원래 집합의 복사본을 만듭니다 (그리고 백그라운드 작업이 그 사본을 사용하는 유일한 스레드는 것을, 확인) (예를 들어,
  • synchronized 블록으로 컬렉션의 모든 사용을 보호를 컬렉션 자체를 "모니터"객체로 사용하는 것이 더 좋지만 전용 모니터 객체 사용).
+0

itr.remove(), itr.add() –

+0

정말 멋진 +1을 사용하여 컬렉션을 반복하면서 컬렉션을 수정할 수 있다는 점을 정확하게 알려주십시오. – Blackbelt

관련 문제