Why does HashMap.get(key) needs to be synchronized when change operations are synchronized?
Asked Answered
T

1

6

I use the .get(...), .put(...) and .clear() operations from multiple threads on one HashMap. .put(...) and .clear() are inside a synchronized block but .get(...) is not. I can't imagine that this will cause problems but in other code I've seen .get() is pretty much always synchronized.

relevant code for get/put

Object value = map.get(key);
if(value == null) {
  synchronized (map) {
    value = map.get(key); // check again, might have been changed in between
    if(value == null) {
      map.put(key, new Value(...));
    }
  }
}

and clear is just:

synchronized (map) {
  map.clear();
}

The write operations will invalidate caches because of the synchronized and the get(...) returns either null or an instance. I can't really see what could go wrong or what would improve by putting the .get(...) operation into a synchronized(map) block.

Twilley answered 30/8, 2015 at 18:56 Comment(1)
This is why the java.util.concurrent.locks.ReadWriteLock was created.Velutinous
S
6

Here is one simple scenario that would produce a problem on unsynchronized get:

  • Thread A starts get, computes the hash bucket number, and gets pre-empted
  • Thread B calls clear(), so a smaller array of buckets gets allocated
  • Thread A wakes up, and may run into the index-out-of-bounds exception

Here is a more complex scenario:

  • Thread A locks the map for an update, and gets pre-empted
  • Thread B initiates a get operation, computes the hash bucket number, and gets pre-empted
  • Thread A wakes up, and continues the put, and realizes that the buckets need resizing
  • Thread A allocates new buckets, copies old content into them, and adds the new item
  • Thread B wakes up, and continues the search using the old bucket index on the new array of buckets.

At this point, thread B is probably not going to find the right item, because it is very likely to be in a hash bucket at a different index. That is why get needs to be synchronized as well.

Sardonyx answered 30/8, 2015 at 19:3 Comment(1)
All of the above can happen in a sequentially consistent execution of the program, but Java doesn't even guarantee SC. So even if all the problems described here were to be somehow avoided, get would still have to be synchronized.Womack

© 2022 - 2024 — McMap. All rights reserved.