August 20th, 2015
(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: email@example.com
I’m helping a co-worker write concurrent code in Java. I’m reminded, once again, that Clojure is easier. In Java, we must wrestle with the issue of synchronized blocks. We have an operation that reads a value from a hashmap and then deletes the key from the hashmap. We are using the hashmap almost like a queue: many threads might read from this hashmap, and yet we only want one thread to read from this hashmap. Therefore, both the read and the delete need to happen in a single atomic operation, so we must wrap them in a synchronized block.
A HashMap is not guaranteed to have atomic operations. Calling any of its methods from different threads (even size()) may corrupt the map. However, a map obtained using Collections.synchronizedMap will have each call synchronized (and hence thread-safe).
However, you may need higher-level synchronization. For instance, if you test whether a key is present, read the size, or otherwise access something from the map and then do something else with the map based on the result, the map may have changed between the two calls. In that case, you need a synchronized block to make the entire transaction atomic, rather than a synchronized map (that just makes each call atomic).