最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

multithreading - Does CompletableFuture ensure field update visibility after join() in Java? - Stack Overflow

programmeradmin0浏览0评论

I’m working with CompletableFuture in Java and want to understand how field updates made inside a CompletableFuture task are visible to the main thread after calling join(). Specifically, if I pass an object (x) to a CompletableFuture task, and the task updates a field inside that object (e.g., x.y), will the main thread always see the updated value after join()?

class Y {
    private int value;
    private List<String> names;

    public Y() {
        this.names = new ArrayList<>();
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void addName(String name) {
        this.names.add(name);
    }

    public List<String> getNames() {
        return names;
    }
}

class X {
    private Y y;

    public void setY(Y y) {
        this.y = y;
    }

    public Y getY() {
        return y;
    }
}

public class Main {
    public static void main(String[] args) {
        X x = new X();

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            Y newY = new Y();
            newY.setValue(42);
            newY.addName("Alice");
            newY.addName("Bob");
            x.setY(newY); // Update the y field of x
        });

        future.join(); // Wait for the CompletableFuture to complete

        // Will the main thread always see the updated y field?
        System.out.println("Value: " + x.getY().getValue()); // Should print 42
        System.out.println("Names: " + x.getY().getNames()); // Should print [Alice, Bob]
    }
}

Are the updated fields (value and names) of x.y always guaranteed to be visible to the main thread after join()? Or I have to use AtomicInteger, volatile or Collections.synchronizedList to achive that?

In my humble opinion the join() method ensures that all actions performed by the CompletableFuture task are completed before the main thread proceeds. This means that any updates to fields or objects made by the CompletableFuture task will be visible to the main thread after join() returns. But I'm not sure about memory visibility of these fields. They might not be visible always.

Note: This example is a simplified reflection of a more complex scenario. In practice, I understand that I could directly set the x object after CompletableFuture completes (e.g., x = future.join()). However, my actual use case involves nested objects and shared state across multiple threads, which is why I’m focusing on field visibility and thread safety.

I’m working with CompletableFuture in Java and want to understand how field updates made inside a CompletableFuture task are visible to the main thread after calling join(). Specifically, if I pass an object (x) to a CompletableFuture task, and the task updates a field inside that object (e.g., x.y), will the main thread always see the updated value after join()?

class Y {
    private int value;
    private List<String> names;

    public Y() {
        this.names = new ArrayList<>();
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void addName(String name) {
        this.names.add(name);
    }

    public List<String> getNames() {
        return names;
    }
}

class X {
    private Y y;

    public void setY(Y y) {
        this.y = y;
    }

    public Y getY() {
        return y;
    }
}

public class Main {
    public static void main(String[] args) {
        X x = new X();

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            Y newY = new Y();
            newY.setValue(42);
            newY.addName("Alice");
            newY.addName("Bob");
            x.setY(newY); // Update the y field of x
        });

        future.join(); // Wait for the CompletableFuture to complete

        // Will the main thread always see the updated y field?
        System.out.println("Value: " + x.getY().getValue()); // Should print 42
        System.out.println("Names: " + x.getY().getNames()); // Should print [Alice, Bob]
    }
}

Are the updated fields (value and names) of x.y always guaranteed to be visible to the main thread after join()? Or I have to use AtomicInteger, volatile or Collections.synchronizedList to achive that?

In my humble opinion the join() method ensures that all actions performed by the CompletableFuture task are completed before the main thread proceeds. This means that any updates to fields or objects made by the CompletableFuture task will be visible to the main thread after join() returns. But I'm not sure about memory visibility of these fields. They might not be visible always.

Note: This example is a simplified reflection of a more complex scenario. In practice, I understand that I could directly set the x object after CompletableFuture completes (e.g., x = future.join()). However, my actual use case involves nested objects and shared state across multiple threads, which is why I’m focusing on field visibility and thread safety.

Share Improve this question edited Feb 6 at 19:44 Kaepxer asked Feb 6 at 19:34 KaepxerKaepxer 4127 silver badges20 bronze badges 3
  • This might answer your question: stackoverflow.com/a/34444996/402428 – michid Commented Feb 7 at 11:56
  • 1 The answer is about how changes in the main thread (before submitting a task) are visible to the worker thread but my question is the opposite. I want to know if changes made by the worker thread (inside CompletableFuture) are visible to the main thread. So I'm not sure answer could be same in opposite case actually. That's a great post though, thanks for sharing it! – Kaepxer Commented Feb 7 at 17:11
  • 1 This comment may be relevant. – Slaw Commented Feb 7 at 20:25
Add a comment  | 

1 Answer 1

Reset to default 4

Docs of java.util.concurrent define happen-before relation:

The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation.

So if actions, that are made by the CompletableFuture task, happen-before return from join, then the field (x.y) updates are visible to your main thread.

I have not found in the doc that CompletableFuture.join shares the same guarantees with Future.get.
But there is a comment in https://bugs.openjdk.org/browse/JDK-8292365 with suggestion to document CompletableFuture guarantees:

Actions taken by the asynchronous computation represented by a {@code Future} happen-before actions subsequent to the retrieval of the result via {@code Future.get()}, {@code Future.resultNow()} , or {@code Future.exceptionNow()}, in another thread.
Similar for the computation represented by a {@code CompletabeFuture} and retrieval of the result via {@code CompletabeFuture.getNow} or {@code CompletabeFuture.join}.

This inclines me to think that CompletableFuture.join shares the same guarantees with Future.get but it is not documented yet.
And it is stated in the doc that actions made by Future.get happen-before actions after it is called:

Actions taken by the asynchronous computation represented by a Future happen-before actions subsequent to the retrieval of the result via Future.get() in another thread.

发布评论

评论列表(0)

  1. 暂无评论