Right.  CyclicBarrier will not do but Phaser would.<br><br><a href="http://download.java.net/jdk7/docs/api/java/util/concurrent/Phaser.html">http://download.java.net/jdk7/docs/api/java/util/concurrent/Phaser.html</a><br>
<br>.. with Java 6 compatible version available from <a href="http://gee.cs.oswego.edu/dl/concurrency-interest/">http://gee.cs.oswego.edu/dl/concurrency-interest/</a><br><br>Each subtask would arrive (without waiting) until all have arrived and then the Phaser&#39;s onAdvance action would notify the central server.<br>
<br>--Joe<br><br><div class="gmail_quote">On Sat, Dec 19, 2009 at 12:14 AM, Enno Shioji <span dir="ltr"></span>wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi Joe,<br>
<br>
<br>
Thank you for your answer!<br>
<br>
I fail to get though how a CyclicBarrier could be used here. I mean,<br>
we&#39;ll have bunch of threads waiting on a barrier for no good reason..<br>
In our app, we&#39;ll have thousands of Tasks with hundreds of subtasks<br>
per Task, so it will become a context switch nightmare..<br>
<br>
Or am I missing something?<br>
<br>
<br>
Regards,<br>
<font color="#888888">Enno<br>
</font><div><div></div><div class="h5"><br>
<br>
<br>
On Sat, Dec 19, 2009 at 3:47 PM, Joe Bowbeer wrote:<br>
&gt; By your description, this seems like a job for CyclicBarrier (or Phaser in<br>
&gt; Java 7).<br>
&gt;<br>
&gt; The barrier task, triggered when all subtasks have completed, would report<br>
&gt; to the central server.<br>
&gt;<br>
&gt; On Fri, Dec 18, 2009 at 10:21 PM, Enno Shioji wrote:<br>
&gt;&gt;<br>
&gt;&gt; Hi All,<br>
&gt;&gt;<br>
&gt;&gt; I came up with 2 kinds of solution to solve a particular problem, of<br>
&gt;&gt; which one seems to me simple enough. The other one however, attempts<br>
&gt;&gt; to manipulate the way JVM reorders using AtomicStampedReference to<br>
&gt;&gt; optimize, and I was wondering whether this is a good idea (in<br>
&gt;&gt; general).<br>
&gt;&gt;<br>
&gt;&gt; To give a little background, a bunch of servers will compute results<br>
&gt;&gt; of sub-tasks that belong to a single task and report them back to the<br>
&gt;&gt; central server. This piece of code is used to register the results,<br>
&gt;&gt; and also check whether all the subtasks for the task has completed and<br>
&gt;&gt; if so, report that fact only once. For simplicity, null checks, access<br>
&gt;&gt; level modifiers etc. are omitted.<br>
&gt;&gt;<br>
&gt;&gt; The important point is that, all task must be reported once and only<br>
&gt;&gt; once as soon as it is completed (completed means all subTaskResults<br>
&gt;&gt; are set).<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; So, here is the first, simple solution:<br>
&gt;&gt;<br>
&gt;&gt; class Task {<br>
&gt;&gt;    //Populate with bunch of (Long, new AtomicReference()) pairs<br>
&gt;&gt;    //Actual app uses read only HashMap<br>
&gt;&gt;    Map&lt;Id, AtomicReference&lt;SubTaskResult&gt;&gt; subtasks = populatedMap();<br>
&gt;&gt;<br>
&gt;&gt;    Semaphore permission = new Semaphore(1);<br>
&gt;&gt;<br>
&gt;&gt;    public Task set(id, subTaskResult){<br>
&gt;&gt;           subtasks.get(id).set(result);<br>
&gt;&gt;           return check() ? this : null;<br>
&gt;&gt;    }<br>
&gt;&gt;<br>
&gt;&gt;    private boolean check(){<br>
&gt;&gt;          for(AtomicReference ref : subtasks){<br>
&gt;&gt;              if(ref.get()==null){<br>
&gt;&gt;                  return false;<br>
&gt;&gt;              }<br>
&gt;&gt;          }//for<br>
&gt;&gt;          return permission.tryAquire();<br>
&gt;&gt;    }<br>
&gt;&gt;<br>
&gt;&gt;  }//class<br>
&gt;&gt;<br>
&gt;&gt; Now, here is a naive optimization attempt that I think is not thread-safe:<br>
&gt;&gt;<br>
&gt;&gt; class Task {<br>
&gt;&gt;    //Populate with bunch of (Long, new AtomicReference()) pairs<br>
&gt;&gt;    //Actual app uses read only HashMap<br>
&gt;&gt;    Map&lt;Id, AtomicReference&lt;SubTaskResult&gt;&gt; subtasks = populatedMap();<br>
&gt;&gt;    AtomicInteger counter = new AtomicInteger(subtasks.size());<br>
&gt;&gt;<br>
&gt;&gt;    public Task set(id, subTaskResult){<br>
&gt;&gt;           //null check omitted<br>
&gt;&gt;           subtasks.get(id).set(result);<br>
&gt;&gt;           //In the actual app, if !compareAndSet(null, result) return<br>
&gt;&gt; null;<br>
&gt;&gt;           return check() ? this : null;<br>
&gt;&gt;    }<br>
&gt;&gt;<br>
&gt;&gt;    private boolean check(){<br>
&gt;&gt;           return counter.decrementAndGet() == 0;<br>
&gt;&gt;    }<br>
&gt;&gt;<br>
&gt;&gt;  }//class<br>
&gt;&gt;<br>
&gt;&gt; I concluded a thread can observe a decremented counter (by another<br>
&gt;&gt; thread) before the result is set in AtomicReference (by that other<br>
&gt;&gt; thread) because of reordering.<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; So, I thought for a while and came up with this idea:<br>
&gt;&gt; Solution III<br>
&gt;&gt;<br>
&gt;&gt; class Task {<br>
&gt;&gt;    //Populate with bunch of (Long, new AtomicStampedReference()) pairs<br>
&gt;&gt;    //Actual app uses read only HashMap<br>
&gt;&gt;    Map&lt;Id, AtomicStampedReference&lt;SubTaskResult&gt;&gt; subtasks =<br>
&gt;&gt; populatedMap();<br>
&gt;&gt;    AtomicInteger counter = new AtomicInteger(subtasks.size());<br>
&gt;&gt;<br>
&gt;&gt;    public Task set(id, subTaskResult){<br>
&gt;&gt;           AtomicStampedReference ref = subtasks.get(id);<br>
&gt;&gt;           ref.set(subTaskResult,-1);<br>
&gt;&gt;           int count = counter.decrementAndGet();<br>
&gt;&gt;           ref.attemptStamp(subTaskResult, count);<br>
&gt;&gt;           return count == 0;<br>
&gt;&gt;    }<br>
&gt;&gt;<br>
&gt;&gt;  }//class<br>
&gt;&gt;<br>
&gt;&gt; I reasoned that, because now there is a dependency (and reordering<br>
&gt;&gt; will be detectable), the JVM must call set(subTaskResult) before<br>
&gt;&gt; calling decrementAndGet(), and thus this implementation becomes thread<br>
&gt;&gt; safe.<br>
&gt;&gt;<br>
&gt;&gt; Am I reasoning right? Also, is it permissive to try manipulating<br>
&gt;&gt; reordering like this?<br>
&gt;&gt;<br>
&gt;&gt; Thank you.<br>
&gt;&gt;<br></div></div></blockquote></div>