3

I have the following error:

Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1584)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1607)
at Server$1.run(Server.java:149)
at java.base/java.lang.Thread.run(Thread.java:832)

Reffering to this code:

    for (Session key : sessions.keySet()) {
                        if (key.getPort2() != port && key.getPort1() != port) { // change later to ip
                            System.out.println("2nd time init 2 client");

                            session.setIp2(ip);
                            session.setPort2(port);

                            sessionID++;

                            sessions.put(session, sessionID);

                            // reset session
                            session = null;

                        }
                    }

Could you explain why this happens?

duh ikal
  • 161
  • 1
  • 8
  • 1
    Does this answer your question? [Why is a ConcurrentModificationException thrown and how to debug it](https://stackoverflow.com/questions/602636/why-is-a-concurrentmodificationexception-thrown-and-how-to-debug-it) – SRJ Feb 13 '21 at 17:05

3 Answers3

2

HashMap and the collections returned by its entrySey, keySet or values methods, do not allow changes (insertion, deletion) while iterating over it. You can create a temporary list to loop over while still changing the original map:

for (Session key : new ArrayList<>(sessions.keySet())) {
    ...
    sessions.put(session, sessionID);
    ...
}

You can also create a temporary list to store the elements to be inserted (after the loop).


Not the question, but not sure what that part is for:

// reset session
session = null;

kind of dangerous -> NullPointerException on following iterations (assuming if block is executed)

  • session is an object i put inside a HashMap called sessions. At this example it's being restored thats why i set it to null and is being in some other part of my code recreated only to be re-added. But what exactly do you mean its dangerous? session = null is not the hashmap itself. – duh ikal Feb 13 '21 at 19:19
  • I could not see that in posted code.... sorry. –  Feb 13 '21 at 19:31
  • It's ok sir. But i found a soluation. – duh ikal Feb 13 '21 at 19:34
  • prefect, very nice! –  Feb 13 '21 at 19:36
  • And what exactly do you mean that it's dangerous? – duh ikal Feb 13 '21 at 19:54
  • `session = null` ... `session.setIp2(ip)` -> `NullPointerException` (dangerous is probably not the best term, so I used *dangerous*) since the variable session is not being set inside the loop –  Feb 13 '21 at 20:56
1

You modify the map while you iterate over its content, which forbidden.

Almost all collection classes forbid this for a good reason. Lets assume you have a collection which contains

a b c g h i j k l

Now you iterate over the elements and while processing element k you insert d. Would you expect that d is skipped because you are already bejond that position? What if you are at position b and insert an m? Would you expect that m will be processed? Or would you expect that new elements will not be processed because they did not exist at the time when you started iterating?

If Java would allow that, people would complain about unexpected behavior. And that is the reason why Java does not allow it. It is one major goal of Java to avoid unexpected behavior, compared to older programming languages.

To solve this, create a second temporary empty map before you start iterating. Then inside your loop you can put new elements into that temporary map. Then finally combine them:

Map<String, String> tmp=new HashMap<>();
for (Session key : sessions.keySet()) {
   ...
   tmp.put(session, sessionID);
}
sessions.putAll(tmp);

This way it is clear what happens, no unexpected behavior.

Stefan
  • 1,789
  • 1
  • 11
  • 16
-3

java.util.HashMap is not thread safe if you are looping through the HashMap elements and at the same time if you try to modify it JVM will through ConcurrentModificationException. You can either iterate the HashMap element by Iterator or use ConcurrentHashMap instead.