26

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:

  1. Actions in the thread that completes a CompletableFuture happen-before any completions dependent stages are executed
  2. Actions in the thread that registers a completion creates a dependent stage happen-before the completion dependent stage is executed

There's a note in java.util.concurrent documentation saying that:

Actions in a thread prior to the submission of a Runnable to an Executor happen-before its execution begins. Similarly for Callables submitted to an ExecutorService.

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:

  1. Are the two hypothetical properties above true or not?
  2. Is there any specific documentation anywhere about the presence or lack of memory visibility guarantees when working with 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?

A.L.
  • 760
  • 5
  • 13
  • 1
    Can you clarify what you mean by "thread that registers a completion" – Misha Dec 23 '15 at 10:51
  • 1
    @Misha: the OP obviously means a *completion action* or a dependent stage. – Holger Dec 23 '15 at 11:55
  • 1
    @Holger if he means completion action, then the two questions are the same. It's more plausible that he means dependent stage. – Misha Dec 23 '15 at 12:04
  • 1
    @Misha: I meant “completion action” in the sense of “action to be performed on completion”, i.e. as submitted via `thenRun`. I admit that this is ambiguous, so, since all submitting methods also create a dependent stage, the term “dependent stage” should be preferred here. – Holger Dec 23 '15 at 12:20
  • @Misha @Holger Sorry for any ambiguity. By "a completion" I meant the function passed to `thenRun` etc. Are "creating a dependent stage" and "executing a dependent stage" the best terms here? – A.L. Dec 23 '15 at 18:27
  • I edited the question to clarify the terms and add a code example. – A.L. Dec 23 '15 at 18:58

1 Answers1

5
  1. 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.

  2. This is basically covered by the documentation of Executor.

Stefan Ferstl
  • 5,135
  • 3
  • 33
  • 41
  • 1
    Thanks for your answer! What I'm struggling to understand is that, for example regarding 2, if the thread that completes the future is different from the thread that creates the dependent stage, what establishes the _happens-before_ relation between actions in the thread that creates the dependent stage and the execution of the dependent stage? Wouldn't the _happens-before_ relation guaranteed by `Executor` only guarantee the relation between actions in the thread that completes the future and the execution of the dependent stage? – A.L. Dec 24 '15 at 00:19
  • 1
    @AapoLaitinen The handover between two threads will always go through an `Executor`. So there is by definition a *happens-before* relationship. Completing the Future has the semantics of `Future#get()` which does also establish a *happens-before* relationship. – Stefan Ferstl Dec 24 '15 at 06:17