CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list
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?  How do I run action after
the future completes?

-Nathan

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list

On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list
It may be better to say "the action return happens before completion". I would expect this to be the case - that is, no additional efforts are needed to make the effects of the action to be visible to any subsequent handler.

Alex

On Thu, 7 Nov 2019, 21:43 Martin Buchholz via Concurrency-interest, <[hidden email]> wrote:

On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list

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:

On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list
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, <[hidden email]> 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:

On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list
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, <[hidden email]> 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:

On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list
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, <[hidden email]> 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, <[hidden email]> 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:

On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer

JSR166 Concurrency mailing list
Ah!  Thank you!  That makes working with CompletableFutures much easier!  I can attach all sorts of things without having to worry about keeping a reference to the returned CompletableFuture.

On Thu, Nov 7, 2019 at 5:55 PM Alex Otenko <[hidden email]> wrote:
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, <[hidden email]> 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, <[hidden email]> 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:

On Thu, Nov 7, 2019 at 10:49 AM Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


--
-Nathan

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest