Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this code cause a ConcurrentModificationException in Java?

Tags:

java

Why does this code cause a ConcurrentModificationException in Java?

public class MainMenuState {
    protected void init() {
        this.addElements(
             new GUIElement()
             .addMousePressed((e, element) -> {
                   this.elements.add(new GUIElement()
                   .addMouseEntered((e, element) -> //...)
             }
        )
   );
}

addElements is defined as:

void addElements(GameElement... elements){
    this.elements.addAll(Arrays.asList(elements));
}

I expect the code to create another GUIElement and add it to list elements when I click the enclosing GUIElement. Instead, when it is clicked, a ConcurrentModificationException is thrown. I understand that ConcurrentModificationException is thrown when a list is modified while elements are being added to it, but mouseEntered isn't called until after elements has been modified.

So how is this error occurring?

The error text:

Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(Unknown Source)
at java.util.LinkedList$ListItr.next(Unknown Source)
at java.lang.Iterable.forEach(Unknown Source)
at code.state.GameState.render(GameState.java:34)
at code.state.Handler.render(Handler.java:32)
at code.state.Handler.render(Handler.java:28)
at code.frame.GameEngine.render(GameEngine.java:94)
at code.frame.GameEngine.run(GameEngine.java:68)
at java.lang.Thread.run(Unknown Source)
like image 362
No Name Avatar asked Mar 04 '26 17:03

No Name


2 Answers

I don't think there's enough context here to pinpoint exactly the cause of your issue. But one solution would be simply to use:

 List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());

to instantiate the problematic list to simple synchronize access to it.

like image 75
Ulises Avatar answered Mar 06 '26 08:03

Ulises


I'm assuming you're rendering something to screen in the code.frame.GameEngine.render() method. The problem is you're using a LinkedList which is not thread-safe. Thus, it's possible to add a new GUIElement to elements while code.frame.GameEngine.render() method is iterating over elements (this happens asynchronously). You need to use a thread-safe collection like:

List<GUIElement> elements = Collections.synchronizedList(new LinkedList<GUIElement>());
like image 25
Austin Avatar answered Mar 06 '26 07:03

Austin