Проблема с ConcurrentModificationException

#java #exception

#java #исключение

Вопрос:

Я пытаюсь создать игру для взлома кирпичей, но я получаю ConcurrentModificationException в этой области.
Я использую Netbeans. Это в моем BlockBreakerPanel классе, и в нем содержится основная информация для того, чтобы мой код действительно работал должным образом. Местоположение исключения имеет ** вокруг него.
Я не знаю, почему я получаю это исключение, и мне интересно, связано ли это с Arraylist и если я как-то неправильно его реализовал.

 public class BlockBreakerPanel extends JPanel implements KeyListener {

ArrayList<Block> blocks;
Block ball;
Block paddle;

JFrame mainFrame, startScreen;

Thread thread;

void reset() {
    blocks = new ArrayList<Block>();
    ball = new Block(237, 435, 35, 25, "ball.png");
    paddle = new Block(175, 480, 150, 25, "paddle.png");
    for (int i = 0; i < 8; i  ) {
        blocks.add(new Block((i * 60   2), 0, 60, 25, "blue.png"));
    }
    for (int i = 0; i < 8; i  ) {
        blocks.add(new Block((i * 60   2), 25, 60, 25, "green.png"));
    }
    for (int i = 0; i < 8; i  ) {
        blocks.add(new Block((i * 60   2), 50, 60, 25, "yellow.png"));
    }
    for (int i = 0; i < 8; i  ) {
        blocks.add(new Block((i * 60   2), 75, 60, 25, "red.png"));
    }

    addKeyListener(this);
    setFocusable(true);
}

BlockBreakerPanel(JFrame frame, JFrame startScreen) {

    this.mainFrame = frame;
    this.startScreen = startScreen;

    reset();

    thread = new Thread(() -> {
        while (true) {
            update();
            try {
                Thread.sleep(10);
            } catch (InterruptedException err) {
                err.printStackTrace();
            }
        }
    });
    thread.start();

}
**public void paintComponent(Graphics g) {
    super.paintComponent(g);
    blocks.forEach(block -> {
        block.draw(g, this);
    });
    ball.draw(g, this);
    paddle.draw(g, this);
}**
public void update() {
    ball.x  = ball.movX;
    
    if (ball.x > (getWidth() - 25) || ball.x < 0) {
        ball.movX *= -1;
    }

    if (ball.y < 0 || ball.intersects(paddle)) {
        ball.movY *= -1;
    }

    ball.y  = ball.movY;

    if (ball.y > getHeight()) {
        thread = null;
        reset();
        mainFrame.setVisible(false);
        startScreen.setVisible(true);

    }
    blocks.forEach(block -> {
        if (ball.intersects(block) amp;amp; !block.destroyed) {
            block.destroyed = true;
            ball.movY *= -1;
        }
    });
    repaint();

}

@Override
public void keyTyped(KeyEvent e) {
    // TODO Auto-generated method stub

}

@Override
public void keyPressed(KeyEvent e) {

    if (e.getKeyCode() == KeyEvent.VK_RIGHT amp;amp; paddle.x < (getWidth() - paddle.width)) {
        paddle.x  = 15;
    }

    if (e.getKeyCode() == KeyEvent.VK_LEFT amp;amp; paddle.x > 0) {
        paddle.x -= 15;
    }

}

@Override
public void keyReleased(KeyEvent e) {
    // TODO Auto-generated method stub

}
 

}

Комментарии:

1. Что такое blocks и где вы его обновляете?

2. blocks это созданный мной arraylist, содержащий различные изображения PNG, которые образуют блоки. blocks = new ArrayList<Block>();

3. Нет, к сожалению, это не @luk2302. Я бы хотел, чтобы это произошло. Мне нужно исправить код и как он должен выглядеть по сравнению с тем, что у меня есть.

4. из какой строки кода исходит исключение? что такое полная трассировка стека?

5. Да, он отвечает на вопрос в том смысле, что он описывает, что такое исключение, почему оно возникает и как его предотвратить.


Ответ №1:

Я подозреваю, что суть вашей проблемы в том, что вы используете отдельный поток для взаимодействия с элементами графического интерфейса. Это недопустимо в Java, элементы пользовательского интерфейса AWT / Swing не являются потокобезопасными. Вы должны выполнять все взаимодействия с пользовательским интерфейсом в потоке отправки событий. Как правило, это очень просто для обычных интерактивных ситуаций. Однако в вашем случае вам необходимо, чтобы задача пользовательского интерфейса выполнялась периодически. Когда вам требуется периодическое обновление элементов пользовательского интерфейса в Java, вы должны использовать таймер swing. Это гарантирует, что ваши обновления будут выполняться потокобезопасным способом пользовательского интерфейса.

Комментарии:

1. Итак, какие изменения мне нужно внести в код в этом классе специально для его работы? Что мне нужно добавить в какие конкретные методы?

2. @joey ты прочитал все ссылки, которые я предоставил? вам нужно прекратить использование потока и начать использовать таймер переключения