[concurrency-interest] Java ForkJoin demo applications

David Holmes davidcholmes at aapt.net.au
Thu Dec 8 18:07:36 EST 2011


Heinz M. Kabutz writes:
> Thanks Doug.  I had read that comment, but did not realize the
> implications.  Like most of the 10_000_000 Java programmers out there,
> I'm still new to Fork/Join.  For example, I found it interesting to
> discover that all the F/J threads are daemons.  Also that you cannot
> interrupt the threads using the standard cancel() mechanism.  This makes
> sense, of course, as F/J is meant to be used to do a calculation in
> parallel, not to call blocking methods.
>
> I wrote a little class that demonstrates the visibility of state
> nicely.  If you run it, the compute() method forks two tasks.  f2 is
> reading running, which happens to be its own field.  As a result, the
> value is typically inlined and so changes are not visible anymore.  Task
> f1 sleeps for a second and then sets the field to "false".  The main
> task does a join on f1, so that thread sees the value change, as you
> explained.  The other thread, however, keeps on running forever.

So to be clear this is exactly as expected. There is no synchronization
action between the two tasks that causes a happens-before relationship
between the reads and writes of "running". So in this case "running" must be
a volatile field.

> The daemon threads make this whole exercise a bit deceptive.  Let's say
> we do not join() the thread that was forked.  That would probably be a
> coding mistake.  But if we did that, then the task would occupy one core
> at 100% and there would be no way to cancel it.

What has this got to do with the thread being a daemon ? The daemon state of
a thread only influences when the VM can terminate.

Any thread spinning in a tight infinite loop can not be cancelled as there
are no "cancellation points" in the loop. Your only recourse there would be
to try Thread.stop().

David
-----


> import java.util.concurrent.*;
>
> /**
>  * @author Heinz Kabutz
>  */
> public class ForkVisibility extends RecursiveAction {
>   private static class ChangeRunningFlag extends RecursiveAction {
>     private final WatchRunningFlag wrf;
>
>     private ChangeRunningFlag(WatchRunningFlag wrf) {
>       this.wrf = wrf;
>     }
>
>     protected void compute() {
>       try {
>         Thread.sleep(1000);
>       } catch (InterruptedException e) {
>         // not sure what to do with the interrupted exception here
>         Thread.currentThread().interrupt();
>       }
>       wrf.running = false;
>     }
>   }
>
>   private static class WatchRunningFlag extends RecursiveAction {
>     private boolean running = true;
>
>     protected void compute() {
>       while (running) ;
>       System.out.println("We have stopped running");
>     }
>   }
>
>   protected void compute() {
>     WatchRunningFlag f2 = new WatchRunningFlag();
>     f2.fork();
>
>     ChangeRunningFlag f1 = new ChangeRunningFlag(f2);
>     f1.fork();
>
>     f1.join();
>     System.out.println("running = " + f2.running);
>
>     System.out.println("Now let's wait for WatchRunningFlag");
>     f2.join();
>     System.out.println("f2.isDone() = " + f2.isDone());
>   }
>
>   public static void main(String[] args) throws InterruptedException {
>     ForkJoinPool pool = new ForkJoinPool();
>     ForkVisibility f = new ForkVisibility();
>     pool.invoke(f);
>     System.out.println(pool);
>   }
> }
>
> Regards
>
> Heinz
> --
> Dr Heinz M. Kabutz (PhD CompSci)
> Author of "The Java(tm) Specialists' Newsletter"
> Sun Java Champion
> IEEE Certified Software Development Professional
> http://www.javaspecialists.eu
> Tel: +30 69 72 850 460
> Skype: kabutz
>
>
>
> On 12/8/11 11:09 PM, Doug Lea wrote:
> > On 12/08/11 16:01, Dr Heinz M. Kabutz wrote:
> >> Hi Doug,
> >>
> >> in your Fib example:
> >>
http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/loops/Fib.java?
revision=1.5&view=markup
>>
>>
>>
>> should "number" not be marked as volatile, as it is accessed from
>> multiple threads?
>>
>
> No. See The javadocs for some explanation. Pasting from the spec for
> ForkJoinTask.fork:
>
> Subsequent modifications to the state of this task or any data it
> operates on are not necessarily consistently observable by any thread
> other than the one executing it unless preceded by a call to join()
> or related methods, or a call to isDone()  returning true.
>
> As far as memory effects go, reading the results of a joined
> computation are basically the same as reading data after
> reading a volatile "ready" flag. Usually (in both cases)
> you do not need to declare the data itself volatile.
>
> -Doug
>
>
_______________________________________________
Concurrency-interest mailing list
Concurrency-interest at cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



More information about the Concurrency-interest mailing list