ConcurrentModificationException в многопоточном приложении Java - PullRequest
0 голосов
/ 25 октября 2019

У меня следующая проблема: мы делаем многопоточную игру, и существует Server, который расширяет Thread и является хостом игры, а также GameUpdater, который также расширяет Thread и являетсяпрототип игрового движка. Проблема в том, что GameUpdater добавляет и удаляет некоторый объект в игре, а Server отправляет Client все обновления (пример приведен ниже):

private void sendUpdatedAsteroids() {
        Collection<Asteroid> asteroids = this.game.getAsteroids();
        StringBuilder existentAsteroids = new StringBuilder();
        for(Asteroid asteroid : asteroids) {
            if (!asteroid.isDestroyed()) {
                existentAsteroids.append(asteroid.getUniqueID());
                existentAsteroids.append("@");

                Message message = new Message();
                message.encryptObject(asteroid);
                try {
                    this.sendMessage(message);
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        }


        Message message = new Message(MessageType.GENERAL, existentAsteroids.toString());
        try {
            sendMessage(message);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

Всегда возникает следующая ошибка:

    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)

Я думаю, что проблема в том, что GameUpdater удаляет и добавляет объекты, а затем Server пытается отправить Client несуществующие объекты. Решение проблемы было найдено: сделать копию астероидов и затем отправить ее на Client, но проблема в том, что она занимает много памяти. Любые другие решения приветствуются (например, заставить два разных потока работать вместе).

1 Ответ

0 голосов
/ 25 октября 2019

Если обновления элемента в списке (добавление / удаление) реже сравниваются с итерацией, я бы предложил рассмотреть CopyOnWriteArrayList. Если не используется частая запись, она эффективна для безопасной итерации.

В противном случае Collections.SynchronizedList может использоваться с синхронизированным блоком поверх итерации списка. Это заставит другой поток ждать, пока итерация не завершится

...