2009-11-29 10 views
15

Hey SO Gurus im ein Heck eines Auftrags mit diesem Code mitjava.util.ConcurrentModificationException in Non Multithreaded-Programm

public void kill(double GrowthRate, int Death) 
{ 
    int before = population.size(); 
    for (PopulationMember p : population) 
    { 
     int[] probs = ProbablityArrayDeath(GrowthRate,Death,(int)p.fitness()); 
     if (probs[RandomNumberGen.nextRandomInt(0, 99)]==0) 
     { 
      population.remove(p); 
     } 
    } 
    System.out.println("Intial Population: "+before+", Deaths:"+(before-   population.size())+", New Population: "+population.size()); 
} 

Wenn ich mein Programm zum ersten Mal den Code versucht, laufen zu laufen! Er hat diesen Fehler

Exception in thread "main" java.util.ConcurrentModificationException 
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793) 
    at java.util.HashMap$KeyIterator.next(HashMap.java:828) 
    at Genetics.Population.kill(Population.java:181) 
    at Genetics.Population.run(Population.java:47) 
    at Control.Main.main(Main.java:35) 

um ein bisschen glotzten Nachdem dies ein Fehler zu sein scheint, die normalerweise mit einem Gewinde passiert, warum sie versuchen, die gleiche Ressource gleichzeitig zugreifen, aber das ist, was ich überhaupt in diesem System nicht immer im, Multithreading.

Kann jemand erklären, warum dies geschieht, oder ein Hack denken um es

Vielen Dank^_^

Antwort

41

Sie können die zugrunde liegende Collection der Iterator (die in der for-each Schleife versteckt ist) ändern. Der richtige Weg, dies zu tun ist:

for (Iterator<PopulationMember> it = population.iterator(); it.hasNext();) { 
    PopulationMemeber p = it.next(); 
    int[] probs = ProbablityArrayDeath(GrowthRate,Death,(int)p.fitness()); 
    if (probs[RandomNumberGen.nextRandomInt(0, 99)] == 0) { 
     it.remove(); 
    } 
} 
+0

Danke, das hat einen großen Teil meines Codes funktioniert – Gwilym

12

Sie nicht die for each Schleife verwenden können, um, wenn man die Dinge aus der Sammlung entfernen.
Sie müssen eine Iterator verwenden und den aktuellen Objektaufruf Iterator.remove entfernen.

Sonst erkennt der zugrundeliegende Iterator, den die for-each-Schleife hinter den Kulissen für Sie erstellt, nicht, wie sich die Sammlung, die er durchläuft, ändert, und sagt Ihnen, dass sie während der Iteration geändert wird.

+0

Dank macht dies eine Menge Sinn – Gwilym

+0

Iterators tun sie nicht unbedingt zur Durchführung dieses Verfahrens haben (pro http://java.sun.com/javase/6/docs/api/java/util/ Iterator.html # remove% 28% 29). –

+0

@ Kaleb - in diesem Fall sollte man Dinge während der Iteration überhaupt nicht entfernen. – abyx

8

Sie haben einen Iterator über die Population, der unter einer for-Schleife verborgen ist. Sie entfernen ein Element aus der Grundgesamtheit während der Iterator-Arbeit. Iterator kann nicht mehr arbeiten, weil Sie die Sammlung in der Mitte der Iteration geändert haben.

Es bezieht sich nicht auf Multithreading.

+0

vielen Dank aswell – Gwilym

4

Eine Abhilfe eine Sammlung kopieren sein. Iterieren Sie über die Kopie und entfernen Sie Elemente aus der ursprünglichen Sammlung.

public void kill(double GrowthRate, int Death) { 
    int before = population.size(); 
    Collection<PopulationMember> forIteration = new HashSet<PopulationMember>(population); 
    for (PopulationMember p : forIteration) { 
     int[] probs = ProbablityArrayDeath(GrowthRate,Death,(int)p.fitness()); 
     if (probs[RandomNumberGen.nextRandomInt(0, 99)]==0) { 
      population.remove(p); 
     } 
    } 
    System.out.println("Intial Population: "+before+", Deaths:"+(before - population.size())+", New Population: "+population.size()); 

}

+2

Dies funktioniert, wenn Sie nicht leicht iterator.remove() aus irgendeinem Grund aufrufen können. –