středa 27. července 2011

Proč je v Jave obtížné psat thread safe

 
final Map m = new HashMap();

ExecutorService executorService = Executors.newFixedThreadPool(1);

Callable<Object> callable = new Callable<Object>() {
 public Object call() throws Exception {
      m.put("test", "test") 
      return null;         
 }
};

Future<Object> future = executorService.submit(callable);
future.get();

assertTrue(m.contains("test"));

Protože ani po deseti letech intenzivního používání Javy si nejsem absolutně jistý jestli je tenhle kód thread safe a nebo není. Thread safe to IMHO není, protože ta mapa není zapisovaná a čtená přes stejný zámek. Na druhou stranu, pokud by ta blokujici fronta uvnitř ExecutorService a zápis do Future objektu způsobil flush (synchronized nebo lock tam bude) lokální cache obouch těch vláken, tak by to fungovat mohlo. Ale spoléhejte na to. Osobně bych tu mapu zasynchronizoval a nebo použil ConcurrentHashMap. Je to thread-safe díky sémantice happen-before, která je tranzitivní a podle javadocu java.util.concurrent zaručena pro vložení tasku a získání jeho výsledk./p>

  • 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.