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

Nathan and Ila Reynolds nathanila at gmail.com
Thu Nov 7 19:39:42 EST 2019


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 
> <mailto: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
>>     <mailto: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
>     <mailto: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/20191107/99d6a704/attachment.html>


More information about the Concurrency-interest mailing list