[英]ThreadLocal: why changes made by one thread is visible in other thread
[英]Are latest changes made to shared context object between consecutive java CompletionStages always visible to each thread executing the lambda
package org.stackoverflow.example;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MeetPlay {
private static final class Context {
List<String> data = new ArrayList<>();
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors());
Context context = new Context();
CompletableFuture.completedFuture(context)
.thenAcceptAsync(c -> context.data.add("1"), executor)
.thenAcceptAsync(__ -> context.data.add("2"), executor)
.thenAcceptAsync(__ -> {
if (context.data.contains("1") && context.data.contains("2")) {
System.out.println("Will that always be the case");
} else {
System.out.println("Or not");
}
}, executor);
}
}
我目前的理解是,无论执行程序使用多少线程、阶段和项目,或者上下文 object 有多“复杂”(例如,具有更多嵌套字段),上面的代码将始终打印:“将始终如此” ,由于发生在 java 完成阶段之间的保证之前。
一位同事认为这不能保证,并说他已经通过经验证明了这一点,但是,我实际上并没有亲眼看到它。 在那之前,我想知道你们怎么想,最重要的是为什么。 参考将不胜感激!
编辑:问题是关于围绕共享上下文的 memory 可见性保证,而不是每个阶段是否在前一个阶段完成后执行。
你是对的 - 这些阶段是按顺序执行的。 这可以通过运行以下代码来证明:
CompletableFuture.completedFuture(context)
.thenAcceptAsync(c -> {
context.data.add("1");
System.out.println("1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}, executor)
.thenAcceptAsync(__ -> {
context.data.add("2");
System.out.println("2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}, executor)
.thenAcceptAsync(__ -> {
if (context.data.contains("1") && context.data.contains("2")) {
System.out.println("Will that always be the case");
} else {
System.out.println("Or not");
}
}, executor);
结果将是:
1
(pause 1 sec)
2
(pause 1 sec)
Will that always be the case
发生这种情况是因为从 thenAcceptAsync 返回的 CompletionStage 仅在操作完成后完成。 即,如果动作异常完成,CompletionStage 也会异常完成。 此行为与 thenAccept 相同。 thenAcceptAsync 中的“异步”仅表示将使用另一个执行器执行操作。
如果要并行执行,请考虑以下代码:
CompletableFuture<Context> f = CompletableFuture.completedFuture(context);
f.thenAcceptAsync(c -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
context.data.add("1");
System.out.println("1");
}, executor);
f.thenAcceptAsync(__ -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
context.data.add("2");
System.out.println("2");
}, executor);
f.thenAcceptAsync(__ -> {
if (context.data.contains("1") && context.data.contains("2")) {
System.out.println("Will that always be the case");
} else {
System.out.println("Or not");
}
}, executor);
这里3个阶段添加到同一个阶段,而不是一个接一个。 一个阶段的完成和另一个阶段的开始之间没有依赖关系。 所以阶段可以并行执行。 结果将是:
Or not
(pause 1 sec)
2
1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.