title: minimizing lock scope for JDK8 ConcurrentHashMap check-and-set operation
body: <p>1.</p>
  
  <p>I have multiple threads updating a ConcurrentHashMap. 
  Each thread appends a list of integers to the Value of a map entry based on the key. 
  There is no removal operation by any thread.</p>
  
  <p><strong>The main point here is that I want to minimize the scope of locking and synchronization as much as possible.</strong> </p>
  
  <p>I saw that the doc of computeIf...() method says "Some attempted update operations on this map by other threads may be blocked while computation is in progress", which is not so encouraging. On the other hand, when I look into its source code, I failed to observe where it locks/synchronizes on the entire map. </p>
  
  <p>Therefore, I wonder about the <strong>comparison of theoretical performance</strong> of using computeIf...() and the following home-grown 'method 2'.  </p>
  
  <p>2.</p>
  
  <p>Also, I feel that the problem I described here is perhaps one of the <strong>most simplified check-n-set (or generally a 'compound') operation you can carry out on ConcurrentHashMap</strong>. </p>
  
  <p>Yet I'm not quite confident and <strong>can't quite find much guideline</strong> about how to do even this kind of simple compound operations on ConcurrentHashMap, <strong>without Locking/Synchronizing on the entire map</strong>.   </p>
  
  <p>So any general good practice advice for this will be much appreciated. </p>
  
  <pre><code>public void myConcurrentHashMapTest1() {
  
      ConcurrentHashMap&lt;String, List&lt;Integer&gt;&gt; myMap = new ConcurrentHashMap&lt;String, List&lt;Integer&gt;&gt;();
  
      // MAP KEY: a Word found by a thread on a page of a book 
      String myKey = "word1";
  
      // -- Method 1: 
      // Step 1.1 first, try to use computeIfPresent(). doc says it may lock the
      //      entire myMap. 
      myMap.computeIfPresent(myKey, (key,val) -&gt; val.addAll(getMyVals()));
      // Step 1.2 then use computeIfAbsent(). Again, doc says it may lock the
      //      entire myMap. 
      myMap.computeIfAbsent(myKey, key -&gt; getMyVals());    
  }
  
  public void myConcurrentHashMapTest2() {        
      // -- Method 2: home-grown lock splitting (kind of). Will it theoretically 
      //      perform better? 
  
      // Step 2.1: TRY to directly put an empty list for the key
      //      This may have no effect if the key is already present in the map
      List&lt;Integer&gt; myEmptyList = new ArrayList&lt;Integer&gt;();
      myMap.putIfAbsent(myKey, myEmptyList);
  
      // Step 2.2: By now, we should have the key present in the map
      //      ASSUMPTION: no thread does removal 
      List&lt;Integer&gt; listInMap = myMap.get(myKey);
  
      // Step 2.3: Synchronize on that list, append all the values 
      synchronized(listInMap){
          listInMap.addAll(getMyVals());
      }
  
  }
  
  public List&lt;Integer&gt; getMyVals(){
      // MAP VALUE: e.g. Page Indices where word is found (by a thread)
      List&lt;Integer&gt; myValList = new ArrayList&lt;Integer&gt;(); 
      myValList.add(1);
      myValList.add(2);
  
      return myValList;
  }
  </code></pre>