Гарантия видимости с помощью thenAccept от CompletableFuture

Я пытаюсь понять, есть ли какие-либо гарантии видимости, предоставляемые CompletableFuture.

Предположим, у меня есть класс с именем SampleClass, который выглядит примерно так:

public class SampleClass {
    private String member1;
    private String member2;
    // getters, setters and constructor;
}

И я делаю что-то вроде этого:

SampleClass sampleClass = new SampleClass();

CompletableFuture<Void> cf1 = CompletableFuture.supplyAsync(() -> "Hello")
        .thenAccept(sampleClass::setMember1);

CompletableFuture<Void> cf2 = CompletableFuture.supplyAsync(() -> " World")
        .thenAccept(sampleClass::setMember2);

cf1.join();
cf2.join();

// sout(sampleClass);

Теперь я хочу понять, что в операторе sout может ли быть случай, когда один или оба члена не инициализированы?

В принципе, есть ли здесь какие-либо гарантии видимости, предоставляемые CompletableFuture? (У меня сложилось впечатление, что CompletableFuture не дает такой гарантии, а приведенный выше код не работает.)

Я уже рассмотрел этот вопрос, но думаю, что это не то, что мне нужно .


person Lavish Kothari    schedule 03.05.2020    source источник
comment
join() — это удобная альтернатива get(). И Future.get() было рассмотрено в документация по пакету. Конечно, было бы неплохо, если бы они расширили эту часть для функций Java 8. Но я по-прежнему считаю его нынешнюю форму достаточной для обеспечения правильной видимости памяти. С одной оговоркой, другого завершения быть не должно. Поскольку любой может вызвать complete на CompletableFuture, такой вызов аннулирует любые гарантии любого завершения, поскольку вы не знаете, что выиграет.   -  person Holger    schedule 04.05.2020
comment
Спасибо @Holger за комментарий. Я понял, на что ты намекаешь. Таким образом, Future.get() гарантирует, что произойдет до любого действия, следующего за Future.get(), поэтому вызов cf2.join() должен видеть обновленное значение sampleClass. Правильно ли я понимаю? И этой гарантии видимости не будет, если откуда-то мы позвоним CompletableFuture.complete(), верно?   -  person Lavish Kothari    schedule 04.05.2020
comment
Точно. В случае нескольких попыток завершения все равно будет существовать отношение происходит до между завершением, которое «выиграло», и действиями после join(), однако вам потребуется безопасный способ определить, какое завершение было выполнено. был. Для типичного случая вычисления функций, которые выдают результат, безопасно использовать значение, возвращаемое join(), так как оно является результатом успешного завершения. Но это не работает для побочного эффекта, такого как setMember2. То же самое относится к CompletableFuture.anyOf(c1, c2).join(); это не даст вам никаких гарантий.   -  person Holger    schedule 05.05.2020
comment
@Holger большое спасибо за это отличное объяснение! Это было действительно полезно.   -  person Lavish Kothari    schedule 07.05.2020