java.util.ConcurrentModificationException в не многопоточной программе - PullRequest
15 голосов
/ 29 ноября 2009

Привет, ТАК Гуру, у меня одна работа с этим кодом

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)

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

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

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

Ответы [ 4 ]

41 голосов
/ 29 ноября 2009

Вы можете изменить базовый 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();
    }
}
12 голосов
/ 29 ноября 2009

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

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

8 голосов
/ 29 ноября 2009

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

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

4 голосов
/ 26 ноября 2010

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

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

}

...