java.util.ConcurrentModificationException en un programa no multiproceso
-
08-07-2019 - |
Pregunta
Hola SO Guru, estoy teniendo un excelente trabajo con este código
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());
}
Cuando ejecuto mi programa la primera vez que intenta ejecutar el código, aparece este error
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)
Habiendo mirado un poco esto parece ser un error que normalmente ocurre con los hilos por los que intentan acceder al mismo recurso al mismo tiempo, pero esto es lo que me hace no tener múltiples hilos en este sistema.
¿Alguien puede explicar por qué sucede esto o pensar en un truco para solucionarlo?
Muchas gracias ^ _ ^
Solución
Puede modificar la Collection
subyacente del Iterator
(que está oculto en el bucle for-each
).
La forma correcta de hacer esto es:
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();
}
}
Otros consejos
No puede utilizar el para cada bucle
si elimina elementos de la colección.
Debe usar un Iterator
y para eliminar el elemento actual llame a Iterator.remove
.
De lo contrario, el iterador subyacente que el bucle for-each crea para usted detrás de escena no comprende cómo está cambiando la colección por la que está pasando, le dice que se está cambiando mientras lo itera.
Tienes un iterador sobre la población oculto bajo un bucle for. Está eliminando un elemento de la población en medio del trabajo del iterador. Iterator ya no puede funcionar porque cambiaste la colección en medio de la iteración.
No está relacionado con subprocesos múltiples.
Una solución alternativa puede ser copiar una colección. Iterar sobre la copia y eliminar elementos de la colección original.
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());
}