java.util.Исключение ConcurrentModificationException в программе, не являющейся многопоточной

StackOverflow https://stackoverflow.com/questions/1816196

Вопрос

Эй, так у меня, Гуру, чертовски сложная работа с этим кодом

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

Когда я запускаю свою программу при первой попытке запустить код, она выдает эту ошибку

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)

Немного поразмыслив, кажется, что это ошибка, которая обычно возникает с потоками, почему они пытаются получить доступ к одному и тому же ресурсу одновременно, но это то, что заставляет меня вообще не заниматься многопоточностью в этой системе.

Кто-нибудь может объяснить, почему это происходит, или придумать способ обойти это

Большое спасибо ^_^

Это было полезно?

Решение

Вы можете изменить базовый Collection Iterator (который скрыт в цикле for-each ). Правильный способ сделать это:

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

Другие советы

Вы не можете использовать для каждого цикла , если удаляете вещи из коллекции.
Вы должны использовать Iterator и удалить текущий вызов элемента Iterator.remove .

В противном случае основной итератор, который цикл for-each создает для вас за кулисами, не понимает, почему происходит изменение коллекции, через которую он проходит, сообщает, что она изменяется, пока вы выполняете итерацию.

У вас есть итератор для заполнения, скрытый под циклом for. Вы удаляете элемент из популяции во время работы итератора. Итератор больше не может работать, потому что вы изменили коллекцию во время итерации.

Это не связано с многопоточностью.

Обходным решением может быть копирование коллекции.Выполните итерацию по копии и удалите элементы из исходной коллекции.

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

}

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top