2009-11-29 5 views
15

Hey im SO de Guru ayant un diable d'un emploi avec ce codejava.util.ConcurrentModificationException dans Non multithread Programme

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()); 
} 

Quand je lance mon programme la première fois qu'il tente d'exécuter le code, il frappe cette erreur

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) 

Après avoir Goggled autour d'un peu cela semble être une erreur qui se produit normalement avec des fils pourquoi ils essaient et l'accès en même temps la même ressource, mais c'est ce que je ne suis pas me faire multithreading du tout dans ce système.

Quelqu'un peut-il expliquer pourquoi cela se produit, ou penser à un hack pour contourner

Un grand merci^_^

Répondre

41

Vous pouvez modifier le Collection sous-jacent du Iterator (qui est masqué dans la boucle for-each). La bonne façon de le faire est:

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

merci cela a une grande partie de mon code de travail – Gwilym

12

Vous ne pouvez pas utiliser la boucle for each si vous supprimez les choses de la collection.
Vous devez utiliser un Iterator et pour supprimer l'appel en cours Iterator.remove. Sinon, l'itérateur sous-jacent que la boucle for-each crée pour vous dans les coulisses ne comprend pas comment la collection est en train de changer, vous indique qu'elle est modifiée pendant que vous la parcourez.

+0

grâce ce qui rend beaucoup de – Gwilym

+0

le Do not sence de Iterator nécessairement à mettre en œuvre cette méthode (par http://java.sun.com/javase/6/docs/api/java/util/ Iterator.html # remove% 28% 29). –

+0

@Kaleb - dans ce cas, il ne faut pas supprimer des choses pendant l'itération. – abyx

8

Vous avez un itérateur sur une population cachée sous une boucle for. Vous supprimez un élément de la population au milieu du travail de l'itérateur. Iterator ne peut plus fonctionner car vous avez modifié la collection au milieu de celle-ci.

Ce n'est pas lié au multithreading.

+0

merci beaucoup aussi – Gwilym

4

Une solution peut être copier une collection. Itérer sur la copie et supprimer des éléments de la collection d'origine.

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

Cela fonctionne lorsque vous ne pouvez pas facilement appeler iterator.remove() pour une raison quelconque. –

Questions connexes