CompletableFuture,可变对象和内存可见性

Posted

技术标签:

【中文标题】CompletableFuture,可变对象和内存可见性【英文标题】:CompletableFuture, mutable objects and memory visibility 【发布时间】:2016-03-29 10:24:25 【问题描述】:

我试图了解 Java 8 中的 CompletableFuture 如何与 Java memory model 交互。在我看来,为了程序员的理智,理想情况下,以下内容应该是正确的:

    线程中完成CompletableFuture的操作happen-before任何completions相关阶段都会被执行 线程中注册完成的操作创建了一个依赖阶段发生之前 completion依赖阶段被执行

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

在将Runnable 提交给Executor 之前,线程中的操作happen-before 开始执行。对于Callables 提交到ExecutorService 也是如此。

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

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

这让我想到了我的问题:

    以上两个假设属性是真的还是假的? 在使用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" 添加到 list1 对 lambda 函数可见?是否保证将list1 添加到list2future 的依赖阶段可见?

【问题讨论】:

你能解释一下“注册完成的线程”是什么意思吗 @Misha: OP 显然意味着一个完成动作 或一个依赖阶段。 @Holger 如果他的意思是完成动作,那么这两个问题是相同的。他的意思是依赖阶段更合理。 @Misha:我的意思是“完成动作”,意思是“完成时要执行的动作”,即通过thenRun提交。我承认这是模棱两可的,所以,既然所有的提交方法都会创建一个依赖阶段,那么这里应该首选术语“依赖阶段”。 @Misha @Holger 抱歉有任何歧义。 “完成”是指传递给thenRun 等的函数。“创建依赖阶段”和“执行依赖阶段”是这里的最佳术语吗? 【参考方案1】:

    是的,你的两个假设都是正确的。原因是,CompletableFuture 中的所有*Async() 方法都将使用java.util.concurrent.Executor 进行异步调用。如果您不提供,这将是 common pool 或为每个任务创建 new thread 的 Executor(如果您将公共池的大小限制为 0 或 1)或用户提供的 Executor . 正如您已经发现的那样,Executor 的 documentation 表示:

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

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

    Executor的文档基本涵盖了这个。

【讨论】:

感谢您的回答!我正在努力理解的是,例如关于 2,如果完成未来的线程与创建依赖阶段的线程不同,那么在动作之间建立 happens-before 关系的创建依赖阶段的线程和依赖阶段的执行? Executor保证的happens-before关系不就只保证完成future的线程中的action和依赖阶段的执行之间的关系吗? @AapoLaitinen 两个线程之间的切换将始终通过Executor。因此,根据定义,存在 happens-before 关系。完成 Future 具有 Future#get() 的语义,它也确实建立了 happens-before 关系。

以上是关于CompletableFuture,可变对象和内存可见性的主要内容,如果未能解决你的问题,请参考以下文章

python可变类型和不可变类型

可变于不可变对象分类

python天坑------可变对象

python 内存那些事

python中的可变与不可变对象的区别

Python中的可变对象和不可变对象