簡體   English   中英

在連續 java 之間對共享上下文 object 所做的最新更改是否對執行 lambda 的每個線程始終可見

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM