![](/img/trans.png)
[英]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.