Решение исключения ConcurrentModificationException - PullRequest
2 голосов
/ 10 февраля 2012

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

public void run() {
    int stepCount = 0;
    int dx;
    int dy;
    while (m_threadTrap){
        dx = 0;
        dy = 0;

        synchronized (m_circles) {
            for (Iterator<Circle> it = m_circles.iterator(); it.hasNext();){
                Circle c = it.next(); //Exception thrown here.
                if (c.getDirX() != 0)
                    if (stepCount % c.getDirX() == 0){
                        dx = 1;
                    }
                if (c.getDirY() != 0)
                    if (stepCount % c.getDirY() == 0){
                        dy = 1;                 
                    }

                c.move(dx, dy); 
            }
        }
        if (stepCount == 150000){
            stepCount = 0;
        }
        stepCount++;
    }
}

m_circles в ArrayList of Circles.

И следующая тема:

public void run() {
    while (m_threadTrap){
        int topPosition;
        int bottomPosition;
        int leftPosition;
        int rightPosition;
        ArrayList<Circle> removedCircles = new ArrayList<Circle>();
        synchronized (m_circles.getCircles()) {
            for (Iterator<Circle> it = m_circles.getCircles().iterator(); it.hasNext();){
                Circle c = it.next();

                // Some calculation to evaluate which circles should be removed
                    removedCircles.add(c);
                }
            }
        }
        try{
            Thread.sleep(25);
        }
        catch (Exception e) { }

        m_circles.getCircles().removeAll(removedCircles);

        if (m_circles.getCircles().size() < 30)
            m_circles.addNewCircle();

        repaint(); 
    }
}

Моя проблема в том, что я получаю исключение ConcurrentModificationException в строке

Circle c = it.next();

в первой теме. Сначала я попытался просмотреть ArrayList с помощью цикла foreach, и это дало мне то же исключение.
После небольшого исследования этого исключения я увидел два решения:
1. Поместить деталь, которая обращается к коллекции, в синхронизированный блок.
2. Использование объекта-итератора коллекции.
Никто из них не решил это за меня.

Ответы [ 2 ]

1 голос
/ 10 февраля 2012

ConcurrentModificationException означает, что вы перебираете коллекцию, и во время перебора кто-то (текущий поток или другой) изменил базовую коллекцию без использования Iterator.remove(). Всякий раз, когда вы вызываете операцию в Итераторе, он проверяет, что базовая коллекция не была изменена. Использование foreach ничего не меняет, поскольку для выполнения цикла используется итератор.

Ваше решение:

  1. создать новую коллекцию:

    для (Круг c: новый ArrayList (m_circles.getCircles ()). Iterator ()) { // Некоторые вычисления, чтобы оценить, какие круги следует удалить removedCircles.add (с); }

  2. или синхронизировать оба потока на одном и том же объекте (вы синхронизируете на разных объектах, поэтому он ничего не делает), когда вы изменяете или обращаетесь к коллекции

1 голос
/ 10 февраля 2012

Чтобы блок synchronized() {} был эффективным, все обращения к защищенным объектам должны быть заключены в синхронизированные блоки.Вы, вероятно, забыли обернуть какой-то доступ.

Еще одна «ошибка» в том, что ConcurrentModificationException также может означать, что он был одновременно изменен в том же потоке .Например, если вы удаляете элемент из коллекции при его обходе, вы можете получить это исключение.(Как исключение, вы можете безопасно удалять элементы через сам итератор)

...