[concurrency-interest] CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

Alex Otenko oleksandr.otenko at gmail.com
Thu Nov 7 19:55:46 EST 2019


The existence of happens before means you write BiConsumer like
single-threaded.

The BiConsumer is attached to this, and a new CompletionStage is retained
until BiConsumer completes, at which stage it is completed. If you drop the
reference to the stage returned by whenComplete, you just won't know when
it completes, and how. But you can't stop its execution by dropping the
reference.

Alex

On Fri, 8 Nov 2019, 00:39 Nathan and Ila Reynolds, <nathanila at gmail.com>
wrote:

> Hmm... I just now recognize that there is a happens before edge for
> whenComplete()'s action returns and when "future" completes.  How does
> having that happens-before edge help write code?  I suppose it allows me to
> carry out actions that must be visible before "future" completes and
> actions that must execute after "future" completes.  Are there other
> abstract or concrete reasons?
>
> > Otherwise the simplified example doesn't make it clear why you do not
> assign async to future.
>
> I could store "async" in a separate field but that wastes heap space when
> I figure I only need 1 field.
>
> I could change startSomething() to the following.  I assume that "unused"
> could be GCed and whenComplete() will never execute.  Is this assumption
> correct?
>
> public void startSomething()
> {
>    CompletableFuture<String> unused;
>
>    future = CompletableFuture.supplyAsync(() -> produce());
>    unused = future.whenComplete((value, throwable) -> doSomething1());
> }
>
> -Nathan
>
> On 11/7/2019 5:30 PM, Alex Otenko wrote:
>
> UnableToInferImplicitsException
>
> You need to start with happens before edges. Some of them are program
> order.
>
> What do you want to happen before future can be seen completed, and what
> do you want to happen after it? Sounds tautological, but that's where you
> need to split the execution into two stages.
>
> Otherwise the simplified example doesn't make it clear why you do not
> assign async to future.
>
> Alex
>
> On Thu, 7 Nov 2019, 23:44 Nathan and Ila Reynolds via
> Concurrency-interest, <concurrency-interest at cs.oswego.edu> wrote:
>
>> UnableToParseQuestionException  ;)
>>
>> Let's use the following simplified code.
>> CompletableFuture<String> future;
>>
>> public void startSomething()
>> {
>>    CompletableFuture<String> async;
>>
>>    async  = CompletableFuture.supplyAsync(() -> produce());
>>    future = async.whenComplete((value, throwable) -> doSomething1());
>> }
>>
>> public String produce()
>> {
>>    Thread.sleep(1000);  // A long operation
>>    return("Hello");
>> }
>>
>> public void doSomething1()
>> {
>>    doSomething2();
>> }
>>
>> public void doSomething2()
>> {
>>    doSomething3();
>> }
>>
>> public void doSomething3()
>> {
>>    doSomething4();
>> }
>>
>> public void doSomething4()
>> {
>>    if (future.getNow(null) == null)
>>       throw new IllegalStateException("I wanted \"Hello\"");
>> }
>>
>> Here are my questions now more refined...
>>
>> Why does "future" not complete until after the action in whenComplete()
>> returns?  How do I exploit this behavior?
>>
>> How do I get the value from "future" in doSomething4()?
>>
>>
>> I could pass the "Hello" value through the doSomething#(), but that will
>> require creating duplicate methods because other code uses the
>> doSomething#() as they are.  I could pass null or value depending on the
>> use case but that makes the methods complicated.
>>
>> I cannot access "async" since that is long gone from the stack of
>> probably another thread.  I could save "async" in a separate field but that
>> wastes heap space.
>>
>> I could change startSomething() to the following.  If I understand
>> correctly, "unused" could be GCed and whenComplete() will never execute.
>>
>> public void startSomething()
>> {
>>    CompletableFuture<String> unused;
>>
>>    future = CompletableFuture.supplyAsync(() -> produce());
>>    unused = future.whenComplete((value, throwable) -> doSomething1());
>> }
>>
>> -Nathan
>>
>> On 11/7/2019 2:41 PM, Martin Buchholz wrote:
>>
>>
>> https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/concurrent/CompletionStage.html#whenComplete(java.util.function.BiConsumer)
>>
>> On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via
>> Concurrency-interest <concurrency-interest at cs.oswego.edu> wrote:
>>
>>> For CompletableStage.whenComplete(), the Javadoc says "The returned
>>> stage is completed when the action returns."  What is the reasoning for
>>> completing the future after action returns?
>>
>>
>> The result of the returned stage depends on whether the action failed or
>> not.
>>
>>
>>> How do I run action after
>>> the future completes?
>>>
>>
>> Why can't you just attach a completion action to either the stage
>> returned by whenComplete or its source?
>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20191108/410f5bba/attachment-0001.html>


More information about the Concurrency-interest mailing list