A few answers on SO mention that the get method in a HashMap can fall into an infinite loop (e.g. this one or this one) if not synchronized properly (and usually the bottom line is "don't use a HashMap in a multi-threaded environment, use a ConcurrentHashMap").
While I can easily see why concurrent calls to the HashMap.put(Object) method can cause an infinite loop, I can't quite see why the get(Object) method can get stuck when it tries to read a HashMap that is being resized at that very moment. I had a look at the implementation in openjdk and it contains a cycle, but the exit condition e != null
should be fulfilled sooner or later. How can it loop forever?
A piece of code that is mentioned explicitly to be vulnerable to this issue is:
public class MyCache {
private Map<String,Object> map = new HashMap<String,Object>();
public synchronized void put(String key, Object value){
map.put(key,value);
}
public Object get(String key){
// can cause in an infinite loop in some JDKs!!
return map.get(key);
}
}
Can someone explain how a thread putting an object into the HashMap and another reading from it can interleave in such a way that an infinite loop is generated? Is it the case that it has to do with some cache coherency issue or CPU instruction reordering (so the problem can only happen on a multi-processor machine)?