2009-11-29 11 views
15

Hey SO im Guru avere un diavolo di un lavoro con questo codicejava.util.ConcurrentModificationException in Non multithreading programma

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

Quando eseguo il mio programma per la prima volta si tenta di eseguire il codice colpisce questo errore

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) 

Avendo stralunate intorno un po 'questo sembra essere un errore che si verifica normalmente con fili per questo che cercano e accedono alla stessa risorsa contemporaneamente, ma questo è ciò che sempre me im non multithreading a tutti in questo sistema.

Qualcuno può spiegare perché questo sta accadendo, o di pensare a un trucco per aggirare l'ostacolo

Molte grazie^_^

risposta

41

È possibile modificare il sottostante Collection dello Iterator (che è nascosto nel ciclo for-each). Il modo corretto per farlo è:

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

grazie a questo ha una grande parte del mio codice funzionante – Gwilym

12

Non è possibile utilizzare il ciclo for each se si rimuove le cose della collezione.
È necessario utilizzare Iterator e rimuovere la chiamata corrente Iterator.remove.

Altrimenti, l'iteratore sottostante che il ciclo for-each crea per te dietro le quinte non capisce come mai la collezione che sta attraversando sta cambiando, ti dice che è stata cambiata mentre la iterate.

+0

grazie questo rende un sacco di Dont sence – Gwilym

+0

di Iterator necessariamente implementare questo metodo (per http://java.sun.com/javase/6/docs/api/java/util/ Iterator.html # rimuovere% 28% 29). –

+0

@Kaleb - nel qual caso non è necessario rimuovere le cose durante l'iterazione. – abyx

8

Hai un iteratore sulla popolazione nascosta sotto un ciclo for. Si sta rimuovendo un oggetto dalla popolazione nel mezzo dell'iteratore in funzione. Iterator non può più funzionare perché hai cambiato la raccolta nel mezzo di iterazione.

Non è correlato al multithreading.

+0

molte grazie anche – Gwilym

4

Una soluzione può essere copiare una collezione. Passare sopra la copia e rimuovere elementi dalla raccolta originale.

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

Questo funziona quando non si può facilmente chiamare iterator.remove() per qualche motivo. –

Problemi correlati