java.util.ConcurrentModificationException в игровом цикле Android

Я использую холст, перемещая объекты на экране, когда объект попадает на левую сторону холста (x=0), создается другой объект того же типа и начинает двигаться на экране.

Все работает отлично, несколько объектов создаются и начинают двигаться по экрану.

В определенный момент я получаю исключение одновременной модификации в моем методе run, где находится игровой цикл, где gameObjs является ArrayList:

@Override
public void run() {

    while(isRunning){
        if(!myHolder.getSurface().isValid())
            continue;
        Canvas canvas = myHolder.lockCanvas();
        canvas.drawRect(0,0,canvas.getWidth(), canvas.getHeight(), pWhite);


        for(MyGameObject gameObj : gameObjs){
            gameObj.move(canvas);
        }

        myHolder.unlockCanvasAndPost(canvas);
    }

}

Я пытался использовать итератор, но все равно получаю ту же ошибку.

Я действительно ценю твою помощь. Заранее спасибо!

1 ответ

Решение

Collections.synchronizedList(...) не будет работать, если что-то подобное происходит... (выдает исключение ConcurrentModificationException...)

public class ConcurrentTest {

    public static void main(String[] args) {
        List<String> things = new ArrayList<>();

        Runnable modifyThread = () -> {
            while(true) {
                for(int k = 0; k < 1000; k++) {
                    things.add(String.valueOf(k));
                }

                while(!things.isEmpty()) {
                    things.remove(0);
                }
            }
        };

        Runnable readThread = () -> {
            while(true) {
                for(String thing : Collections.synchronizedList(things)) {
                    System.out.println(thing);
                }
            }
        };

        new Thread(modifyThread).start();
        new Thread(readThread).start();
    }
}

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

Вы можете взять копию списка, прежде чем перебирать его.

Например, в приведенном выше коде попробуйте...

for(String thing : new ArrayList<>(things)) {

...вместо...

for(String thing : Collections.synchronizedList(things)) {

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

Еще лучше сохранить цикл чтения как...

for(String thing : things) {

... но измените тип списка...

List<String> things = new CopyOnWriteArrayList<>();
Другие вопросы по тегам