Search code examples
javaconcurrencyatomicconcurrenthashmap

ConcurrentHashMap atomic operation to remove all entries except one


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);
    }
});

Solution

  • 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.