effects of executor tasks visible after invokeAll?
If I submit some tasks to an Executor
using invokeAll
, am I guaranteed that the submitted thread sees all the side effects of the task executions, even if I don't call get()
on each of the returned Future
s?
From a practical point of view, it would seem that this would be a useful guarantee, but I don't see anything in the javadoc.
More precisely, do all actions in the body of a Callable
submitted to an executor happen-before the return from the invokeAll()
call?
It's annoying to uselessly call get()
on each future, when in fact the return type is Void
and no exceptions are thrown - all the work in the happens as side-effects.
If invokeAny()
promises that no tasks are still in execution when invokeAny()
returns, this will be the case: all side effects are visible.
In order for invokeAny()
to know that all tasks are done, it needs to have synchronized with those threads, meaning that the returning of the functions happens after the tasks completing (and everything that happens in the task). However the API of 'ExecutorSerive' and 'Future.cancel()' does not explicitly say what happens when you cancel a running task (in particular: will cancel()
wait with returning until the tasks has stopped running. The fact that after calling cancel()
, isDone()
must return true, does imply that cancel()
will not return until the task has actually finished executing.
One more thing to watch out for is that you will not know if a task ever started execution, when using invokeAny()
without inspecting the Future
objects.
From the documentation of ExecutorService:
Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task, which in turn happen-before the result is retrieved via Future.get().
As I read this, there is a memory barrier on task submission, so potentially you'd need to call get()
on the last task in your list to, but not the others.
However, since calling get()
is the only way to determine whether the task completed or threw, I would still call it on every Future
, regardless of memory guarantees.