简体   繁体   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);
    }
}

My current understanding is that code above will always print: "Will that always be the case" no matter how many threads the executor uses, stages and items are involved, or how "complex" the Context object is (eg with more nested fields), due to the happens before guarantee between java completion stages.我目前的理解是,无论执行程序使用多少线程、阶段和项目,或者上下文 object 有多“复杂”(例如,具有更多嵌套字段),上面的代码将始终打印:“将始终如此” ,由于发生在 java 完成阶段之间的保证之前。

A colleague at work argues that is not guaranteed and says he has empirically proven it, however, I haven't actually seen it with my own eyes.一位同事认为这不能保证,并说他已经通过经验证明了这一点,但是,我实际上并没有亲眼看到它。 Until that happens, I was wondering what do you guys think and most importantly WHY .在那之前,我想知道你们怎么想,最重要的是为什么 References will be greatly appreciated!参考将不胜感激!

EDIT: question is regarding the memory visibility guarantees around the shared context and not whether each stage is executed after the previous completes.编辑:问题是关于围绕共享上下文的 memory 可见性保证,而不是每个阶段是否在前一个阶段完成后执行。

You are right - these stages are executed sequentially.你是对的 - 这些阶段是按顺序执行的。 This can be demonstrated by running this code:这可以通过运行以下代码来证明:

    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);

The result will be:结果将是:

1
(pause 1 sec)
2
(pause 1 sec)
Will that always be the case

This happens because CompletionStage returned from thenAcceptAsync completes only after action finishes.发生这种情况是因为从 thenAcceptAsync 返回的 CompletionStage 仅在操作完成后完成。 Ie if action completes exceptionally so will CompletionStage.即,如果动作异常完成,CompletionStage 也会异常完成。 This behaviour is the same as for thenAccept.此行为与 thenAccept 相同。 "Async" in thenAcceptAsync only means that action will be executed using another executor. thenAcceptAsync 中的“异步”仅表示将使用另一个执行器执行操作。

If you want parallel execution consider the following code:如果要并行执行,请考虑以下代码:

    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);

Here 3 stages added to the same stage, not one after another.这里3个阶段添加到同一个阶段,而不是一个接一个。 There is no dependency between one stage's completion and beginning of another.一个阶段的完成和另一个阶段的开始之间没有依赖关系。 So stages may execute in parallel.所以阶段可以并行执行。 The result will be:结果将是:

Or not
(pause 1 sec)
2
1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM