24

我试图了解CompletableFutureJava 8 中如何与Java 内存模型交互。在我看来,对于程序员的理智来说,理想情况下,以下内容应该是正确的:

  1. 线程中完成CompletableFuture 发生之前的操作,任何与完成相关的阶段都被执行
  2. 线程中注册完成的动作会在完成依赖阶段执行之前创建一个依赖阶段

java.util.concurrent 文档中有一条注释说:

线程中的操作在提交RunnableExecutor 发生之前执行之前。同样对于Callables 提交到一个ExecutorService.

这表明第一个属性为真,只要完成未来的线程执行完成依赖阶段或将其提交给Executor. 另一方面,在阅读CompletableFuture 文档后,我不太确定:

为非异步方法的依赖完成提供的操作可以由完成当前的线程执行,也可以由CompletableFuture完成方法的任何其他调用者执行。

这让我想到了我的问题:

  1. 上面的两个假设属性是真的还是假的?
  2. 是否有任何特定文档说明在使用 时是否存在内存可见性保证CompletableFuture

附录:

以具体示例的方式,考虑以下代码:

List<String> list1 = new ArrayList<>();
list1.add("foo");

CompletableFuture<List<String>> future =
        CompletableFuture.supplyAsync(() -> {
            List<String> list2 = new ArrayList<>();
            list2.addAll(list1);
            return list2;
        });

是否保证添加"foo"list1lambda 函数可见?是否保证添加list1list2的依赖阶段是可见的future

4

1 回答 1

5
  1. 是的,你的两个假设都是正确的。原因是,其中的所有*Async()方法都CompletableFuture将使用 ajava.util.concurrent.Executor进行异步调用。如果您不提供,这将是公共池或为每个任务创建一个新线程的 Executor(如果您将公共池的大小限制为 0 或 1)或用户提供的 Executor。正如您已经发现的那样,文档Executor说:

    在将 Runnable 对象提交给 Executor 之前,线程中的操作发生在其执行开始之前,可能在另一个线程中。

    因此,在您的示例中,可以保证它是您的 lambda"foo"的一部分,并且在后续阶段中可见。list1list2

  2. 这基本上由Executor.

于 2015-12-23T23:00:07.440 回答