3

Given a ConcurrentHashMap<String, String> contains following entries:

this.map = new ConcurrentHashMap<>();
this.map.put("user", "user description");
this.map.put("session", "session description");
this.map.put("test", "test description");

The map is accessed by multiple threads.

How to remove all keys, except session in an atomic way?

Will this code work as I expect, without race conditions? Is forEach method atomic? Is there any other way to achieve this atomically?

map.forEach((key, value) -> {
    if (!key.equals("session")) {
        map.remove(key);
    }
});
Naman
  • 27,789
  • 26
  • 218
  • 353
Mariusz.v7
  • 2,322
  • 2
  • 16
  • 24

1 Answers1

1

Your forEach() will not happen atomically, since each remove() call is synchronized independently.

You could try doing this by creating a new map and replacing the old one with it:

ConcurrentMap<String, String> newMap = new ConcurrentHashMap<>();
newMap.put("session", this.map.get("session"));
this.map = newMap;

Threads viewing this.map before the switch will have the old view, but the atomic "removal" can be thought of as taking place when you assign the new map. The only other issue is when another thread modifies the value associated with "session" in the original map between the 2nd and 3rd lines (or if that key isn't even present), but as you said in your comment that never happens.

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • 1
    The solution you proposed is good for me. One more question comes to my mind: what about `forEach()` method? Is it synchronized or not? If it is, then assuming potentially very long operation inside it, what would happen if two threads will try to execute it? One will wait for another, or both will get a copy/view of the map without blocking? – Mariusz.v7 Nov 10 '18 at 16:38
  • No, it's not. Why don't you just test it? Add a Thread.sleep() inside the forEach, and start a thread that uses the map. And you'll know. – JB Nizet Nov 10 '18 at 16:41
  • @JBNizet yes I started to play with it like you just wrote. I just wanted someone more experienced than me to confirm my guesses. – Mariusz.v7 Nov 10 '18 at 16:43
  • 1
    @Mariusz.v7 You can also look at [the source](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/util/concurrent/ConcurrentHashMap.java#l1591) to see this. – arshajii Nov 10 '18 at 16:45