java.util.ConcurrentModificationException in un programma non multithread
-
08-07-2019 - |
Domanda
Hey SO Guru, sto avendo un diavolo di lavoro con questo codice
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 la prima volta che tenta di eseguire il codice, viene visualizzato 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 gorgogliato un po 'questo sembra essere un errore che si verifica normalmente con i thread perché provano ad accedere alla stessa risorsa contemporaneamente, ma questo è ciò che mi fa non essere affatto multithreading in questo sistema.
Qualcuno può spiegare perché questo sta accadendo o pensare a un hack per aggirarlo
Mille grazie ^ _ ^
Soluzione
Puoi modificare la Collection
sottostante di Iterator
(che è nascosta nel ciclo per ogni
).
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();
}
}
Altri suggerimenti
Non puoi usare il per ogni
ciclo se rimuovi oggetti dalla collezione.
Devi usare un Iterator
e per rimuovere la voce dell'elemento corrente Iterator.remove
.
Altrimenti, l'iteratore sottostante che il ciclo for-each crea per te dietro le quinte non capisce come sta cambiando la collezione che sta attraversando, ti dice che sta cambiando mentre lo fai.
Hai un iteratore sulla popolazione nascosto in un ciclo for. Stai rimuovendo un oggetto dalla popolazione durante il funzionamento dell'iteratore. Iterator non può più funzionare perché hai cambiato la raccolta nel mezzo di iterazione.
Non è legato al multithreading.
Una soluzione alternativa può essere la copia di una raccolta. Scorri sulla copia e rimuovi gli 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());
}