Is the following code set up to correctly synchronize the calls on synchronizedMap?
public class MyClass {
private static Map
There is the potential for a subtle bug in your code.
[UPDATE: Since he's using map.remove() this description isn't totally valid. I missed that fact the first time thru. :( Thanks to the question's author for pointing that out. I'm leaving the rest as is, but changed the lead statement to say there is potentially a bug.]
In doWork() you get the List value from the Map in a thread-safe way. Afterward, however, you are accessing that list in an unsafe matter. For instance, one thread may be using the list in doWork() while another thread invokes synchronizedMap.get(key).add(value) in addToMap(). Those two access are not synchronized. The rule of thumb is that a collection's thread-safe guarantees don't extend to the keys or values they store.
You could fix this by inserting a synchronized list into the map like
List valuesList = new ArrayList();
valuesList.add(value);
synchronizedMap.put(key, Collections.synchronizedList(valuesList)); // sync'd list
Alternatively you could synchronize on the map while you access the list in doWork():
public void doWork(String key) {
List values = null;
while ((values = synchronizedMap.remove(key)) != null) {
synchronized (synchronizedMap) {
//do something with values
}
}
}
The last option will limit concurrency a bit, but is somewhat clearer IMO.
Also, a quick note about ConcurrentHashMap. This is a really useful class, but is not always an appropriate replacement for synchronized HashMaps. Quoting from its Javadocs,
This class is fully interoperable with Hashtable in programs that rely on its thread safety but not on its synchronization details.
In other words, putIfAbsent() is great for atomic inserts but does not guarantee other parts of the map won't change during that call; it guarantees only atomicity. In your sample program, you are relying on the synchronization details of (a synchronized) HashMap for things other than put()s.
Last thing. :) This great quote from Java Concurrency in Practice always helps me in designing an debugging multi-threaded programs.
For each mutable state variable that may be accessed by more than one thread, all accesses to that variable must be performed with the same lock held.