I'm trying to understand how CompletableFuture
in Java 8 interacts with the Java memory model. It seems to me that for programmer sanity, the following should ideally hold true:
CompletableFuture
happen-before any There's a note in java.util.concurrent documentation saying that:
Actions in a thread prior to the submission of a
Runnable
to anExecutor
happen-before its execution begins. Similarly forCallable
s submitted to anExecutorService
.
Which would suggest that the first property is true, as long as the thread that completes the future executes the completion dependent stage or submits it to an Executor
. On the other hand, after reading CompletableFuture documentation I'm not so sure about that:
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current
CompletableFuture
, or by any other caller of a completion method.
Which brings me to my questions:
CompletableFuture
?Addendum:
In the way of a concrete example, consider this code:
List<String> list1 = new ArrayList<>();
list1.add("foo");
CompletableFuture<List<String>> future =
CompletableFuture.supplyAsync(() -> {
List<String> list2 = new ArrayList<>();
list2.addAll(list1);
return list2;
});
Is it guaranteed that adding "foo"
to list1
is visible to the lambda function? Is it guaranteed that adding list1
to list2
is visible to the dependent stages of future
?
The CompletableFuture. get() method is blocking. It waits until the Future is completed and returns the result after its completion.
completedFuture(U value) Returns a new CompletableFuture that is already completed with the given value. static <U> CompletionStage<U> completedStage(U value) Returns a new CompletionStage that is already completed with the given value and supports only those methods in interface CompletionStage .
runAsync. Returns a new CompletableFuture that is asynchronously completed by a task running in the given executor after it runs the given action.
Yes, both of your hypotheses are true. The reason is, that all of the *Async()
methods in CompletableFuture
will use a java.util.concurrent.Executor
to make the asynchronous call. If you don't provide one, this will either be the common pool or an Executor that creates a new thread for each task (in case you restrict the size of the common pool to 0 or 1) or a user-provided Executor.
As you already found out, the documentation of the Executor
says:
Actions in a thread prior to submitting a Runnable object to an Executor happen-before its execution begins, perhaps in another thread.
So in your example, it is guaranteed that "foo"
is part of list1
in your lambda and that list2
is visible in subsequent stages.
This is basically covered by the documentation of Executor
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With