title: ConcurrentHashMap of Future and double-check locking
body: <p>Given:</p>
  
  <ul>
  <li>A lazy initialized singleton class implemented with double-check locking pattern with all the relevant <code>volatile</code> and <code>synchronized</code> stuff in <code>getInstance</code>. This singleton launches asynchronous operations via an <code>ExecutorService</code>,</li>
  <li>There are seven type of tasks, each one identified by a unique key,</li>
  <li>When a task is launched, it is stored in a cached based on <code>ConcurrentHashMap</code>,</li>
  <li>When a client ask for a task, if the task in the cache is done, a new one is launched and cached; if it is running, the task is retrieved from the cache and passed to the client.</li>
  </ul>
  
  <p>Here is a excerpt of the code:</p>
  
  <pre><code>private static volatile TaskLauncher instance;
  private ExecutorService threadPool;
  private ConcurrentHashMap&lt;String, Future&lt;Object&gt;&gt; tasksCache;
  
  private TaskLauncher() {
      threadPool = Executors.newFixedThreadPool(7);
      tasksCache = new ConcurrentHashMap&lt;String, Future&lt;Object&gt;&gt;();
  }
  
  public static TaskLauncher getInstance() {
      if (instance == null) {
          synchronized (TaskLauncher.class) {
              if (instance == null) {
                  instance = TaskLauncher();
              }
          }
      }
      return instance;
  }
  
  public Future&lt;Object&gt; getTask(String key) {
      Future&lt;Object&gt; expectedTask = tasksCache.get(key);
      if (expectedTask == null || expectedTask.isDone()) {
          synchronized (tasksCache) {
              if (expectedTask == null || expectedTask.isDone()) {
                  // Make some stuff to create a new task
                  expectedTask = [...];
                  threadPool.execute(expectedTask);
                  taskCache.put(key, expectedTask);
              }
          }
      }
      return expectedTask;
  }
  </code></pre>
  
  <p>I got one major question, and another minor one:</p>
  
  <ol>
  <li>Do I need to perform double-check locking control in my <code>getTask</code> method? I know <code>ConcurrentHashMap</code> is thread-safe for read operations, so my <code>get(key)</code> is thread-safe and may not need double-check locking (but yet quite unsure of this…). But what about the <code>isDone()</code> method of Future?</li>
  <li>How do you chose the right lock object in a <code>synchronized</code> block? I know it must no be <code>null</code>, so I use first the <code>TaskLauncher.class</code> object in <code>getInstance()</code> and then the <code>tasksCache</code>, already initialized, in the <code>getTask(String key)</code> method. And has this choice any importance in fact?</li>
  </ol>