Re: CompletableStage.whenComplete(): Completes the stage after calling the BiConsumer
Nathan and Ila Reynolds via Concurrency-interest <[email protected]>
| Newsgroups | gmane.comp.java.jsr.166-concurrency |
|---|---|
| Message-ID | <CAG7qthBd72LY6UNv0JtUY0EqOOcnV_YAV6T3aVP6a3mW-Nomtw@mail.gmail.com> |
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 <[email protected]> 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, <[email protected]> > 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, <[email protected]> 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 <[email protected]> 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 >>> [email protected] >>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest >>> >> -- -Nathan _______________________________________________ Concurrency-interest mailing list [email protected] http://cs.oswego.edu/mailman/listinfo/concurrency-interest