overview of advanced java 8 completablefuture features ...schmidt/cs891f/2018-pdfs/... · 2...

Post on 15-May-2020

10 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Overview of Advanced Java 8

CompletableFuture Features (Part 2)

Douglas C. Schmidtd.schmidt@vanderbilt.edu

www.dre.vanderbilt.edu/~schmidt

Professor of Computer Science

Institute for Software

Integrated Systems

Vanderbilt University

Nashville, Tennessee, USA

2

Learning Objectives in this Part of the Lesson• Understand advanced features

of completable futures, e.g.

• Factory methods that initiateasync functionality

• Completion stage methods usedto chain together actions that perform async result processing& composition

Exception methods

Completion stage methods

Factory methodsArbitrary-arity

methods

Basic methods

3

Completion Stage Methods Chain Actions Together

4See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html

• A completable future can serve as a ”completion stage” for async result processing

Completion Stage Methods Chain Actions Together

5

• A completable future can serve as a ”completion stage” for async result processing

• An action is performed on a completed async call result

Completion Stage Methods Chain Actions TogetherBigFraction unreduced = BigFraction

.valueOf(new BigInteger

("846122553600669882"),

new BigInteger

("188027234133482196"),

false); // Don’t reduce!

Supplier<BigFraction> reduce = () ->

BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

...

thenApply()’s action is triggered when future from supplyAsync() completes

6

• A completable future can serve as a ”completion stage” for async result processing

• An action is performed on a completed async call result

• Methods can be chainedtogether “fluently”

Completion Stage Methods Chain Actions TogetherBigFraction unreduced = BigFraction

.valueOf(new BigInteger

("846122553600669882"),

new BigInteger

("188027234133482196"),

false); // Don’t reduce!

Supplier<BigFraction> reduce = () ->

BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

.thenAccept(System.out::println);

thenAccept()’s action is triggered when future from

thenApply() completes

See en.wikipedia.org/wiki/Fluent_interface

7

• A completable future can serve as a ”completion stage” for async result processing

• An action is performed on a completed async call result

• Methods can be chainedtogether “fluently”

• Each method registers a lambda action to apply

Completion Stage Methods Chain Actions TogetherBigFraction unreduced = BigFraction

.valueOf(new BigInteger

("846122553600669882"),

new BigInteger

("188027234133482196"),

false); // Don’t reduce!

Supplier<BigFraction> reduce = () ->

BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

.thenAccept(System.out::println);

8

• A completable future can serve as a ”completion stage” for async result processing

• An action is performed on a completed async call result

• Methods can be chainedtogether “fluently”

• Each method registers a lambda action to apply

• A lambda action is called only after previous stage completes successfully

Completion Stage Methods Chain Actions TogetherBigFraction unreduced = BigFraction

.valueOf(new BigInteger

("846122553600669882"),

new BigInteger

("188027234133482196"),

false); // Don’t reduce!

Supplier<BigFraction> reduce = () ->

BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

.thenAccept(System.out::println);

9

• A completable future can serve as a ”completion stage” for async result processing

• An action is performed on a completed async call result

• Methods can be chainedtogether “fluently”

• Each method registers a lambda action to apply

• A lambda action is called only after previous stage completes successfully

Completion Stage Methods Chain Actions TogetherBigFraction unreduced = BigFraction

.valueOf(new BigInteger

("846122553600669882"),

new BigInteger

("188027234133482196"),

false); // Don’t reduce!

Supplier<BigFraction> reduce = () ->

BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

.thenAccept(System.out::println);

Action is “deferred” until previous stage completes & fork-join thread is available

10

• Use completion stages to avoid blocking a thread until the result must be obtained

Completion Stage Methods Chain Actions Together

11

• Use completion stages to avoid blocking a thread until the result must be obtained, e.g.

• Try not to call join() or get()unless absolutely necessary

Completion Stage Methods Chain Actions Together

Servers may avoid blocking completely, whereas clients may need join() sparingly

Join Us

12

• Use completion stages to avoid blocking a thread until the result must be obtained, e.g.

• Try not to call join() or get()unless absolutely necessary

• This approach helps improveresponsiveness

Completion Stage Methods Chain Actions Together

13

• A completable future can serve as a ”completion stage” for async result processing

Completion Stage Methods Chain Actions Together

Juggling is a good analogy for completion stages!

14

Grouping CompletableFutureCompletion Stage Methods

15

• Completion stage methods are grouped based on howa stage is triggered by oneor more previous stage(s)

See www.jesperdj.com/2015/09/26/the-future-is-completable-in-java-8

Exception methods

Completion stage methods

Factory methodsArbitrary-arity

methods

Basic methods

Grouping CompletableFuture Completion Stage Methods

16

• Completion stage methods are grouped based on howa stage is triggered by oneor more previous stage(s)

• Completion of a single previous stage

Methods Params Returns Behavior

thenApply(Async)

Function CompletableFuture with Function result

Apply function to result of the previous stage

thenCompose(Async)

Function CompletableFuture with Function result directly, not a nested future

Apply function to result of the previous stage

thenAccept(Async)

Consumer CompletableFuture<Void>

Consumer handles result of previous stage

thenRun(Async)

Runnable CompletableFuture<Void>

Run action w/out returning value

Grouping CompletableFuture Completion Stage Methods

These methods run in the invoking thread or the same

thread as previous stage

The thread that executes these methods depends on various runtime factors

17

Methods Params Returns Behavior

thenApply(Async)

Function CompletableFuture with Function result

Apply function to result of the previous stage

thenCompose(Async)

Function CompletableFuture with Function result directly, not a nested future

Apply function to result of the previous stage

thenAccept(Async)

Consumer CompletableFuture<Void>

Consumer handles result of previous stage

thenRun(Async)

Runnable CompletableFuture<Void>

Run action w/out returning value

See blog.krecan.net/2013/12/25/completablefutures-why-to-use-async-methods

• Completion stage methods are grouped based on howa stage is triggered by oneor more previous stage(s)

• Completion of a single previous stage

Grouping CompletableFuture Completion Stage Methods

*Async() variants run in common fork-join pool

18

• Completion stage methods are grouped based on howa stage is triggered by oneor more previous stage(s)

• Completion of a single previous stage

• Completion of both of 2 previous stages

• i.e., an “and”

Methods Params Returns Behavior

thenCombine(Async)

BiFunction

CompletableFuture with BiFunction result

Apply bifunctionto results of both previous stages

thenAcceptBoth

(Async)

BiConsumer

CompletableFuture<Void>

BiConsumerhandles results of both previous stages

runAfterBoth

(Async)

Runnable CompletableFuture<Void>

Run action when both previous stages complete

Grouping CompletableFuture Completion Stage Methods

19

• Completion stage methods are grouped based on howa stage is triggered by oneor more previous stage(s)

• Completion of a single previous stage

• Completion of both of 2 previous stages

• Completion of either of 2 previous stages

• i.e., an “or”

Methods Params Returns Behavior

applyToEither

(Async)

Function CompletableFuture with Function result

Apply function to results of either previous stage

acceptEither

(Async)

Consumer CompletableFuture<Void>

Consumer handles results of either previous stage

runAfterEither

(Async)

Runnable CompletableFuture<Void>

Run action when either previous stage completes

Grouping CompletableFuture Completion Stage Methods

20

Key CompletableFutureCompletion Stage Methods

21

• Methods triggered by completion of a single previous stage

• thenApply()

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenApply

(Function<? super T,

? extends U> fn)

{ ... }

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenApply

22

• Methods triggered by completion of a single previous stage

• thenApply()

• Applies a function action to the previous stage’s result

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenApply

(Function<? super T,

? extends U> fn)

{ ... }

23

• Methods triggered by completion of a single previous stage

• thenApply()

• Applies a function action to the previous stage’s result

• Returns a future containingthe result of the action

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenApply

(Function<? super T,

? extends U> fn)

{ ... }

24

• Methods triggered by completion of a single previous stage

• thenApply()

• Applies a function action to the previous stage’s result

• Returns a future containingthe result of the action

• Used for a sync action that returns a value, not a future

Key CompletableFuture Completion Stage MethodsBigFraction unreduced = BigFraction

.valueOf(new BigInteger("..."),

new BigInteger("..."),

false); // Don’t reduce!

Supplier<BigFraction> reduce = ()

-> BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

...

e.g., toMixedString() returns a string value

25

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenCompose

(Function<? super T,

? extends

CompletionStage<U>> fn)

{ ... }

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenCompose

26

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenCompose

(Function<? super T,

? extends

CompletionStage<U>> fn)

{ ... }

27

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• i.e., not a nested future

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenCompose

(Function<? super T,

? extends

CompletionStage<U>> fn)

{ ... }

28

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• i.e., not a nested future

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenCompose

(Function<? super T,

? extends

CompletionStage<U>> fn)

{ ... }

See dzone.com/articles/understanding-flatmap

+ =

≠+thenCompose() is similar to flatMap() on a Stream or Optional

29

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• Used for an async action that returns a completable future

Key CompletableFuture Completion Stage Methods

e.g., supplyAsync() returns a completable future

Function<BF,

CompletableFuture<BF>>

reduceAndMultiplyFractions =

unreduced -> CompletableFuture

.supplyAsync

(() -> BF.reduce(unreduced))

.thenCompose

(reduced -> CompletableFuture

.supplyAsync(() ->

reduced.multiply(...)));

...

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#supplyAsync

30

Function<BF, CompletableFuture<

CompletableFuture<BF>>>

reduceAndMultiplyFractions =

unreduced -> CompletableFuture

.supplyAsync

(() -> BF.reduce(unreduced))

.thenApply

(reduced -> CompletableFuture

.supplyAsync(() ->

reduced.multiply(...)));

...

...

Unwieldy!

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• Used for an async action that returns a completable future

• Avoids unwieldy nesting offutures à la thenApply()

Key CompletableFuture Completion Stage Methods

31

Function<BF,

CompletableFuture<BF>>

reduceAndMultiplyFractions =

unreduced -> CompletableFuture

.supplyAsync

(() -> BF.reduce(unreduced))

.thenApplyAsync(reduced

-> reduced.multiply(...)));

...

...

Concise!

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• Used for an async action that returns a completable future

• Avoids unwieldy nesting offutures à la thenApply()

Key CompletableFuture Completion Stage Methods

thenApplyAsync() can often replace thenCompose(supplyAsync()) nestings

32

supplyAsync() will return a CompletableFuture to a

CompletableFuture here!!

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• Used for an async action that returns a completable future

• Avoids unwieldy nesting offutures à la thenApply()

Key CompletableFuture Completion Stage Methods

Can be used to avoid calling join() when flattening nested completable futures

CompletableFuture<Integer> countF =

.CompletableFuture

.supplyAsync

(() ->

longRunnerReturnsCF())

.thenCompose

(Function.identity())

...

33

This idiom flattens the return value to “just” one CompletableFuture!

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• Used for an async action that returns a completable future

• Avoids unwieldy nesting offutures à la thenApply()

Key CompletableFuture Completion Stage Methods

Can be used to avoid calling join() when flattening nested completable futures

CompletableFuture<Integer> countF =

.CompletableFuture

.supplyAsync

(() ->

longRunnerReturnsCF())

.thenCompose

(Function.identity())

...

34

Runs longBlockerReturnsCF() in a thread in the fork-join pool

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• Applies a function action to the previous stage’s result

• Returns a future containingresult of the action directly

• Used for an async action that returns a completable future

• Avoids unwieldy nesting offutures à la thenApply()

Key CompletableFuture Completion Stage Methods

thenComposeAsync() can be used to avoid calling supplyAsync() again in a chain

CompletableFuture<Integer> countF =

.CompletableFuture

.supplyAsync

(() ->

longRunnerReturnsCF())

.thenComposeAsync

(this::longBlockerReturnsCF)

...

35

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• thenAccept()

Key CompletableFuture Completion Stage MethodsCompletableFuture<Void>

thenAccept

(Consumer<? super T> action)

{ ... }

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenAccept

36

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• thenAccept()

• Applies a consumer action to handle previous stage’s result

Key CompletableFuture Completion Stage MethodsCompletableFuture<Void>

thenAccept

(Consumer<? super T> action)

{ ... }

This action behaves as a “callback” with a side-effect

See en.wikipedia.org/wiki/Callback_(computer_programming)

37

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• thenAccept()

• Applies a consumer action to handle previous stage’s result

• Returns a future to Void

Key CompletableFuture Completion Stage MethodsCompletableFuture<Void>

thenAccept

(Consumer<? super T> action)

{ ... }

38

BigFraction unreduced = BigFraction

.valueOf(new BigInteger("..."),

new BigInteger("..."),

false); // Don’t reduce!

Supplier<BigFraction> reduce = ()

-> BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

.thenAccept(System.out::println);

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• thenAccept()

• Applies a consumer action to handle previous stage’s result

• Returns a future to Void

• Often used at the end of a chain of completion stages

Key CompletableFuture Completion Stage Methods

thenApply() returns a string future that thenAccept() prints when it completes

39

BigFraction unreduced = BigFraction

.valueOf(new BigInteger("..."),

new BigInteger("..."),

false); // Don’t reduce!

Supplier<BigFraction> reduce = ()

-> BigFraction.reduce(unreduced);

CompletableFuture

.supplyAsync(reduce)

.thenApply(BigFraction

::toMixedString)

.thenAccept(System.out::println);

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• thenAccept()

• Applies a consumer action to handle previous stage’s result

• Returns a future to Void

• Often used at the end of a chain of completion stages

Key CompletableFuture Completion Stage Methods

println() is a callback that has a side-effect (i.e., printing the mixed string)

40

• Methods triggered by completion of a single previous stage

• thenApply()

• thenCompose()

• thenAccept()

• Applies a consumer action to handle previous stage’s result

• Returns a future to Void

• Often used at the end of a chain of completion stages

• May lead to “callback hell!”

Key CompletableFuture Completion Stage Methods

See dzone.com/articles/callback-hell

41

• Methods triggered by completion of both of two previous stages

• thenCombine()

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenCombine

(CompletionStage<? Extends U>

other,

BiFunction<? super T,

? super U,

? extends V> fn)

{ ... }

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#thenCombine

42

• Methods triggered by completion of both of two previous stages

• thenCombine()

• Applies a bifunction action to two previous stages’ results

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenCombine

(CompletionStage<? Extends U>

other,

BiFunction<? super T,

? super U,

? extends V> fn)

{ ... }

43

• Methods triggered by completion of both of two previous stages

• thenCombine()

• Applies a bifunction action to two previous stages’ results

• Returns a future containingthe result of the action

Key CompletableFuture Completion Stage MethodsCompletableFuture<U> thenCombine

(CompletionStage<? Extends U>

other,

BiFunction<? super T,

? super U,

? extends V> fn)

{ ... }

44

• Methods triggered by completion of both of two previous stages

• thenCombine()

• Applies a bifunction action to two previous stages’ results

• Returns a future containingthe result of the action

Key CompletableFuture Completion Stage Methods

thenCombine() essentially performs a “reduction”

CompletableFuture<U> thenCombine

(CompletionStage<? Extends U>

other,

BiFunction<? super T,

? super U,

? extends V> fn)

{ ... }

45

• Methods triggered by completion of both of two previous stages

• thenCombine()

• Applies a bifunction action to two previous stages’ results

• Returns a future containingthe result of the action

• Used to “join” two pathsof asynchronous execution

Key CompletableFuture Completion Stage MethodsCompletableFuture<BF> compF1 =

CompletableFuture

.supplyAsync(() ->

/* multiply two BFs. */);

CompletableFuture<BF> compF2 =

CompletableFuture

.supplyAsync(() ->

/* divide two BFs. */);

compF1

.thenCombine(compF2,

BigFraction::add)

.thenAccept(System.out::println);

thenCombine()’s action is triggered when its two

associated futures complete

46

• Methods triggered by completion of either of two previous stages

• acceptEither()

Key CompletableFuture Completion Stage MethodsCompletableFuture<Void> acceptEither

(CompletionStage<? Extends T>

other,

Consumer<? super T> action)

{ ... }

See docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#acceptEither

47

• Methods triggered by completion of either of two previous stages

• acceptEither()

• Applies a consumer actionthat handles either of theprevious stages' results

Key CompletableFuture Completion Stage MethodsCompletableFuture<Void> acceptEither

(CompletionStage<? Extends T>

other,

Consumer<? super T> action)

{ ... }

48

• Methods triggered by completion of either of two previous stages

• acceptEither()

• Applies a consumer actionthat handles either of theprevious stages' results

• Returns a future to Void

Key CompletableFuture Completion Stage MethodsCompletableFuture<Void> acceptEither

(CompletionStage<? Extends T>

other,

Consumer<? super T> action)

{ ... }

49

• Methods triggered by completion of either of two previous stages

• acceptEither()

• Applies a consumer actionthat handles either of theprevious stages' results

• Returns a future to Void

• Often used at the end of achain of completion stages

Key CompletableFuture Completion Stage MethodsCompletableFuture<List<BigFraction>>

quickSortF = CompletableFuture

.supplyAsync(() ->

quickSort(list));

CompletableFuture<List<BigFraction>>

mergeSortF = CompletableFuture

.supplyAsync(() ->

mergeSort(list));

Create two completable futures that will contain the results of

sorting the list using two different algorithms in two different threads

50

• Methods triggered by completion of either of two previous stages

• acceptEither()

• Applies a consumer actionthat handles either of theprevious stages' results

• Returns a future to Void

• Often used at the end of achain of completion stages

Key CompletableFuture Completion Stage MethodsCompletableFuture<List<BigFraction>>

quickSortF = CompletableFuture

.supplyAsync(() ->

quickSort(list));

CompletableFuture<List<BigFraction>>

mergeSortF = CompletableFuture

.supplyAsync(() ->

mergeSort(list));

quickSortF.acceptEither

(mergeSortF, results -> results

.forEach(fraction ->

System.out.println

(fraction

.toMixedString())));

Printout sorted results from which ever sorting routine finished first

acceptEither() does not cancel the second future after the first one completes

51

End of Overview of Advanced Java 8 Completable Future

Features (Part 2)

top related