dagblog.
← Archive

Why it’s hard to write thread-safe Java code


final Map m = new HashMap();
ExecutorService executorService = Executors.newFixedThreadPool(1);
Callable callable = new Callable() {
public Object call() throws Exception {
m.put("test", "test")
return null;
}
};
Future future = executorService.submit(callable);
future.get();
assertTrue(m.contains("test"));
Even after ten years of using Java intensively, I’m still unsure whether this code is thread-safe. I don’t think it is, because reads and writes to the map don’t use the same lock. On the other hand, the blocking queue inside the ExecutorService and the write to the Future object might flush both threads’ local caches (there must be a synchronized block or a lock in there). If so, it could work. But would you rely on that? I’d synchronize access to the map or use a ConcurrentHashMap. The code is thread-safe because the happens-before relationship is transitive. The java.util.concurrent Javadoc guarantees that relationship for submitting a task and retrieving its result.
  • Actions in a thread prior to the submission of a Runnable to an Executor happen-before its execution begins. Similarly for Callables submitted to an ExecutorService.
  • Actions taken by the asynchronous computation represented by a Future happen-before actions subsequent to the retrieval of the result via Future.get() in another thread.

Medium version

Related articles

Related CZ Podcast episodes