0

I have a long-running calculation that I have split up with Java's ForkJoinTask.

Java's FutureTask provides a template method done(). Overriding this method allows for "registering a completion handler".

Is it possible to register a completion handler for a ForkJoinTask?

I am asking because I don't want to have blocking threads in my application - but my application will have a blocking thread as soon as I retrieve the calculation result via calls to result = ForkJoinPool.invoke(myForkJoinTask) or result = ForkJoinPool.submit(myForkJoinTask).get().

Abdull
  • 26,371
  • 26
  • 130
  • 172
  • _"... I don't want to have blocking threads ..."_ -- Please explain in more detail. If you have multiple threads _something_ has to wait for completion to gather results and do something with them. – Jim Garrison Sep 02 '13 at 03:35
  • On "If you have multiple threads something has to wait for completion to gather results and do something with them." This assumption is not true because if you have multiple threads you can make every thread to put its results into some synchronized or atomic data structure and check in every thread if the overall data is complete and then trigger any new activity WITHOUT having an extra "waiting and collecting thread". – user2618802 Feb 24 '22 at 08:02

1 Answers1

1

I think you mean "lock free" programming http://en.wikipedia.org/wiki/Non-blocking_algorithm? While FutureTask.get() possibly blocks the current thread (and thus leaves an idling CPU) ForkJoinTask.get() (or join) tries to keep the CPU busy.

This works well if you are able to split your problem into many small peaces (ForkJoinTask). If one FJTask is internally waiting for the result of an other task, which is not ready, the ForkJoinTask tries to pick up some other work (Task) to do from its ForkJoinPool and executes that task(s) meanwhile.

Until all your Task are CPU bound, it works fine: all your CPU(s) are kept busy. It does NOT work if any of your Task waits for some external event (i.e. sending a REST call to the Mars rover). Also the problem should form a DAG, else you may get a deadlock. But until you join only tasks you forked before in the same Task it works well. Even better if you join the task you forked at last.

So it is not too worse to call get() or join() within/between your Tasks.

You mentioned a completion handler to solve the problem. If you are implementing the ForkJoinTask yourself you may have a look at RecursiveTask or even RecursiveAction. You will implement compute() and you may easily forward the result of each task to some collector at the end of your compute() function instead of returning it.

But you have to consider that you collector will be called concurrently! For adding values or counting completion counts have a look at java.util.concurrent.atomic. Avoid using synchronized blocks. Else all your Tasks have to wait for this single bottleneck and only one CPU keeps working.

I think propagating the results involves more problems than returning them (since FJPool handles this). In addition it becomes difficult to decide (and to communicate to the outside) at which point your final result is done.

Ditz
  • 735
  • 7
  • 17