WeakHashMap is not thread-safe

Karol Dowbecki · July 9, 2020

java.util.WeakHashMap can be used as in-memory cache, allowing keys to expire when they are weakly reachable. Unfortunately this class is not thread-safe. It’s entirely possible that un-synchronized invocation of the WeakHashMap.get(Object) method will result in infinite busy waiting loop starving all other threads.

If we take a look at the WeakHashMap.get(Object) method source code, the culprit is the while loop:

public V get(Object key) {
  Object k = maskNull(key);
  int h = hash(k);
  Entry<K,V>[] tab = getTable();
  int index = indexFor(h, tab.length);
  Entry<K,V> e = tab[index];
  while (e != null) {
    if (e.hash == h && eq(k, e.get()))
        return e.value;
    e = e.next;
  }
  return null;
}

This problem has been discovered in multiple well-known open source project e.g. Tomcat bug #50078 or Jenkins bug #6528. The easiest way to confirm this issue is to take a JVM thread dump and look for a runnable thread reporting java.util.WeakHashMap.get method:

"thread-1" daemon prio=10 tid=0x00001ba07475c800 nid=0x135b runnable [0x0000000028b14000]
  java.lang.Thread.State: RUNNABLE
    at java.util.WeakHashMap.get(WeakHashMap.java:355)
    ...

If you need an in-memory cache and want to avoid thread synchronization, WeakHashMap is the wrong choice.

Twitter, Facebook