ConcurrentModificationException при обновлении изображений спрайтов - PullRequest
0 голосов
/ 03 мая 2019

Я продолжаю получать исключение ConcurrentModificationException при запуске моей игры, которая использует многопоточность для создания новых спрайтов и их перемещения.Основная проблема, кажется, происходит с созданием и / или движением "Шаровых молний".

Мне удалось успешно запустить мою программу без каких-либо исключений, закомментировав метод createNewFireballs.Однако всякий раз, когда я использую метод createNewFireballs, ошибка обычно появляется всякий раз, когда я вызываю функцию, которая обновляет изображение спрайта Fireball (и никогда не происходит для любого другого типа спрайта). Мне было интересно, сможет ли кто-нибудь мне помочьнайдите источник моей проблемы и, возможно, решите проблему.

public synchronized void createNewFireball() {
    new Thread(new Runnable() {
        public void run() {
            while (gameNotPaused && hero.isNotDead()) {
                fireball = new Fireball(dragon.getX(), dragon.getY());
                fireballs.add(fireball);
            try
                {
                Thread.sleep(100); //Waits for .1 second
                }
            catch(InterruptedException e)
                {
                e.printStackTrace();
                Thread.currentThread().interrupt();
                }
            }
        }
    }).start();
}

    //The problem commonly occurs in the update method, 
    //specifically the line  "FireballIter.next().updateImage(g);"
public synchronized void update(Graphics g) {
    Iterator<Sprite> FireballIter = fireballs.iterator();

    Iterator<Sprite> arrowIter = arrows.iterator();
    while (arrowIter.hasNext()) {
        arrowIter.next().updateImage(g);
    }

    Iterator<Sprite> iterator = sprites.iterator(); 
    while (iterator.hasNext()) {
        iterator.next().updateImage(g);
    }

    while (FireballIter.hasNext()) {
        FireballIter.next().updateImage(g);
    }

}
//Although sometimes it occurs as a result of updateScene, which is 
//called in another method which moves all the "projectile" sprites
public synchronized void updateScene(int width, int height) {

    Iterator<Sprite> arrowIter = arrows.iterator();
    while(arrowIter.hasNext()) {
        Sprite spriteObject = arrowIter.next(); 
        ((Arrow) spriteObject).updateState();   
        if (spriteObject.overlaps(dragon, 350, 350)) {
            dragon.arrowHit();
            System.out.printf("Dragon was hit at %d, %d%n, while arrow was at %d,%d%n", dragon.getX(), dragon.getY(), spriteObject.getX(), spriteObject.getY());
            arrowIter.remove();
        }
    }

    Iterator<Sprite> fireballIter = fireballs.iterator();
    while(fireballIter.hasNext()) {
        Sprite spriteObject = fireballIter.next(); 
        ((Fireball) spriteObject).updateState();    
    }
}

@Override
public synchronized void run() {
    while (model.getGameNotPaused()) {
        model.updateScene(view.getWidth(), view.getHeight());
        view.repaint();
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
            JOptionPane.showMessageDialog(null, "Press R to resume game.");
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 03 мая 2019

Предполагая, что ваши огненные шары ArrayList<Fireball>,, вы также можете рассмотреть возможность переключения на CopyOnWriteArrayList , поточно-ориентированный вариант ArrayList

0 голосов
/ 03 мая 2019

Выполнение синхронизации createNewFireball ничего не дает: синхронизация применяется только к выполнению этого метода, а не к исполняемому потоку, выполняемому потоком (что хорошо, потому что в противном случае ни один из других методов не сможет выполняться до тех пор, пока цикл закончен).

Поместите fireballs.add в блок synchronized, следя за тем, чтобы обеспечить синхронизацию на нужной вещи:

  • Если вы просто используете synchronized (this), вы будете синхронизироваться на Runnable.
  • Вместо этого используйте synchronized (TheContainingClass.this) (где TheContainingClass - имя класса, содержащего эти методы).
...