Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Yes, it is correct. volatile protects only that object reference, but nothing else.</p> <p>No, putting an element to a <code>volatile</code> HashMap will not create a happens-before relationship, not even with a <code>ConcurrentHashMap</code>.</p> <p>Actually <code>ConcurrentHashMap</code> does not hold lock for read operations (e.g. <code>containsKey()</code>). See <a href="http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html" rel="nofollow">ConcurrentHashMap</a> Javadoc.</p> <p><strong>Update</strong>:</p> <p>Reflecting your updated question: you have to synchronize on the object you put into the CHM. I recommend to use a <strong>container object</strong> instead of directly storing the <code>Object</code> in the map:</p> <pre><code>public class ObjectContainer { volatile boolean isSetupDone = false; Object o; } static ConcurrentHashMap&lt;String, ObjectContainer&gt; containers = new ConcurrentHashMap&lt;String, ObjectContainer&gt;(); public Object getInstance(String groupId) { ObjectContainer oc = containers.get(groupId); if (oc == null) { // it's enough to sync on the map, don't need the whole class synchronized(containers) { // double-check not to overwrite the created object if (!containers.containsKey(groupId)) oc = new ObjectContainer(); containers.put(groupId, oc); } else { // if another thread already created, then use that oc = containers.get(groupId); } } // leave the class-level sync block } // here we have a valid ObjectContainer, but may not have been initialized // same doublechecking for object initialization if(!oc.isSetupDone) { // now syncing on the ObjectContainer only synchronized(oc) { if(!oc.isSetupDone) { oc.o = new String("typically a more complicated operation")); oc.isSetupDone = true; } } } return oc.o; } </code></pre> <p>Note, that at <em>creation</em>, at most one thread may create <code>ObjectContainer</code>. But at <em>initialization</em> each groups may be initialized in parallel (but at most 1 thread per group). </p> <p>It may also happen that <code>Thread T1</code> will create the ObjectContainer, but <code>Thread T2</code> will initialize it.</p> <p>Yes, it is worth to keep the <code>ConcurrentHashMap</code>, because the map reads and writes will happen at the same time. But <code>volatile</code> is not required, since the map object itself will not change.</p> <p>The sad thing is that the double-check does not always work, since the compiler may create a bytecode where it is reusing the result of <code>containers.get(groupId)</code> (that's not the case with the volatile isSetupDone). That's why I had to use <code>containsKey</code> for the double-checking.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload