Merge paradox/scala/futures.md and java/futures.md (#23397)

This commit is contained in:
Richard Imaoka 2017-07-26 04:09:45 +09:00 committed by Arnout Engelen
parent e5249c69b6
commit e0692b5e93
4 changed files with 326 additions and 354 deletions

View file

@ -1,296 +0,0 @@
# Futures
## Introduction
In the Scala Standard Library, a [Future](http://en.wikipedia.org/wiki/Futures_and_promises) is a data structure
used to retrieve the result of some concurrent operation. This result can be accessed synchronously (blocking)
or asynchronously (non-blocking). To be able to use this from Java, Akka provides a java friendly interface
in `akka.dispatch.Futures`.
See also @ref:[Java 8 Compatibility](java8-compat.md) for Java compatibility.
## Execution Contexts
In order to execute callbacks and operations, Futures need something called an `ExecutionContext`,
which is very similar to a `java.util.concurrent.Executor`. if you have an `ActorSystem` in scope,
it will use its default dispatcher as the `ExecutionContext`, or you can use the factory methods provided
by the `ExecutionContexts` class to wrap `Executors` and `ExecutorServices`, or even create your own.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports1 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #diy-execution-context }
## Use with Actors
There are generally two ways of getting a reply from an `AbstractActor`: the first is by a sent message (`actorRef.tell(msg, sender)`),
which only works if the original sender was an `AbstractActor`) and the second is through a `Future`.
Using the `ActorRef`'s `ask` method to send a message will return a `Future`.
To wait for and retrieve the actual result the simplest method is:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports1 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #ask-blocking }
This will cause the current thread to block and wait for the `AbstractActor` to 'complete' the `Future` with it's reply.
Blocking is discouraged though as it can cause performance problem.
The blocking operations are located in `Await.result` and `Await.ready` to make it easy to spot where blocking occurs.
Alternatives to blocking are discussed further within this documentation.
Also note that the `Future` returned by an `AbstractActor` is a `Future<Object>` since an `AbstractActor` is dynamic.
That is why the cast to `String` is used in the above sample.
@@@ warning
`Await.result` and `Await.ready` are provided for exceptional situations where you **must** block,
a good rule of thumb is to only use them if you know why you **must** block. For all other cases, use
asynchronous composition as described below.
@@@
To send the result of a `Future` to an `Actor`, you can use the `pipe` construct:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #pipe-to }
## Use Directly
A common use case within Akka is to have some computation performed concurrently without needing
the extra utility of an `AbstractActor`. If you find yourself creating a pool of `AbstractActor`s for the sole reason
of performing a calculation in parallel, there is an easier (and faster) way:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports2 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #future-eval }
In the above code the block passed to `future` will be executed by the default `Dispatcher`,
with the return value of the block used to complete the `Future` (in this case, the result would be the string: "HelloWorld").
Unlike a `Future` that is returned from an `AbstractActor`, this `Future` is properly typed,
and we also avoid the overhead of managing an `AbstractActor`.
You can also create already completed Futures using the `Futures` class, which can be either successes:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #successful }
Or failures:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #failed }
It is also possible to create an empty `Promise`, to be filled later, and obtain the corresponding `Future`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #promise }
For these examples `PrintResult` is defined as follows:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #print-result }
## Functional Futures
Scala's `Future` has several monadic methods that are very similar to the ones used by `Scala`'s collections.
These allow you to create 'pipelines' or 'streams' that the result will travel through.
### Future is a Monad
The first method for working with `Future` functionally is `map`. This method takes a `Mapper` which performs
some operation on the result of the `Future`, and returning a new result.
The return value of the `map` method is another `Future` that will contain the new result:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports2 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #map }
In this example we are joining two strings together within a `Future`. Instead of waiting for f1 to complete,
we apply our function that calculates the length of the string using the `map` method.
Now we have a second `Future`, f2, that will eventually contain an `Integer`.
When our original `Future`, f1, completes, it will also apply our function and complete the second `Future`
with its result. When we finally `get` the result, it will contain the number 10.
Our original `Future` still contains the string "HelloWorld" and is unaffected by the `map`.
Something to note when using these methods: passed work is always dispatched on the provided `ExecutionContext`. Even if
the `Future` has already been completed, when one of these methods is called.
### Composing Futures
It is very often desirable to be able to combine different Futures with each other,
below are some examples on how that can be done in a non-blocking fashion.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports3 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #sequence }
To better explain what happened in the example, `Future.sequence` is taking the `Iterable<Future<Integer>>`
and turning it into a `Future<Iterable<Integer>>`. We can then use `map` to work with the `Iterable<Integer>` directly,
and we aggregate the sum of the `Iterable`.
The `traverse` method is similar to `sequence`, but it takes a sequence of `A` and applies a function from `A` to `Future<B>`
and returns a `Future<Iterable<B>>`, enabling parallel `map` over the sequence, if you use `Futures.future` to create the `Future`.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports4 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #traverse }
It's as simple as that!
Then there's a method that's called `fold` that takes a start-value,
a sequence of `Future`:s and a function from the type of the start-value, a timeout,
and the type of the futures and returns something with the same type as the start-value,
and then applies the function to all elements in the sequence of futures, non-blockingly,
the execution will be started when the last of the Futures is completed.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports5 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #fold }
That's all it takes!
If the sequence passed to `fold` is empty, it will return the start-value, in the case above, that will be empty String.
In some cases you don't have a start-value and you're able to use the value of the first completing `Future`
in the sequence as the start-value, you can use `reduce`, it works like this:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports6 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #reduce }
Same as with `fold`, the execution will be started when the last of the Futures is completed, you can also parallelize
it by chunking your futures into sub-sequences and reduce them, and then reduce the reduced results again.
This is just a sample of what can be done.
## Callbacks
Sometimes you just want to listen to a `Future` being completed, and react to that not by creating a new Future, but by side-effecting.
For this Scala supports `onComplete`, `onSuccess` and `onFailure`, of which the last two are specializations of the first.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #onSuccess }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #onFailure }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #onComplete }
## Ordering
Since callbacks are executed in any order and potentially in parallel,
it can be tricky at the times when you need sequential ordering of operations.
But there's a solution! And it's name is `andThen`, and it creates a new `Future` with
the specified callback, a `Future` that will have the same result as the `Future` it's called on,
which allows for ordering like in the following sample:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #and-then }
## Auxiliary methods
`Future` `fallbackTo` combines 2 Futures into a new `Future`, and will hold the successful value of the second `Future`
if the first `Future` fails.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #fallback-to }
You can also combine two Futures into a new `Future` that will hold a tuple of the two Futures successful results,
using the `zip` operation.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #zip }
## Exceptions
Since the result of a `Future` is created concurrently to the rest of the program, exceptions must be handled differently.
It doesn't matter if an `AbstractActor` or the dispatcher is completing the `Future`, if an `Exception` is caught
the `Future` will contain it instead of a valid result. If a `Future` does contain an `Exception`,
calling `Await.result` will cause it to be thrown again so it can be handled properly.
It is also possible to handle an `Exception` by returning a different result.
This is done with the `recover` method. For example:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #recover }
In this example, if the actor replied with a `akka.actor.Status.Failure` containing the `ArithmeticException`,
our `Future` would have a result of 0. The `recover` method works very similarly to the standard try/catch blocks,
so multiple `Exception`s can be handled in this manner, and if an `Exception` is not handled this way
it will behave as if we hadn't used the `recover` method.
You can also use the `recoverWith` method, which has the same relationship to `recover` as `flatMap` has to `map`,
and is use like this:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #try-recover }
## After
`akka.pattern.Patterns.after` makes it easy to complete a `Future` with a value or exception after a timeout.
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports7 }
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #after }
## Java 8, CompletionStage and CompletableFuture
Starting with Akka 2.4.2 we have begun to introduce Java 8 `java.util.concurrent.CompletionStage` in Java APIs.
It's a `scala.concurrent.Future` counterpart in Java; conversion from `scala.concurrent.Future` is done using
`scala-java8-compat` library.
Unlike `scala.concurrent.Future` which has async methods only, `CompletionStage` has *async* and *non-async* methods.
The `scala-java8-compat` library returns its own implementation of `CompletionStage` which delegates all *non-async*
methods to their *async* counterparts. The implementation extends standard Java `CompletableFuture`.
Java 8 `CompletableFuture` creates a new instance of `CompletableFuture` for any new stage,
which means `scala-java8-compat` implementation is not used after the first mapping method.
@@@ note
After adding any additional computation stage to `CompletionStage` returned by `scala-java8-compat`
(e.g. `CompletionStage` instances returned by Akka) it falls back to standard behaviour of Java `CompletableFuture`.
@@@
Actions supplied for dependent completions of *non-async* methods may be performed by the thread
that completes the current `CompletableFuture`, or by any other caller of a completion method.
All *async* methods without an explicit Executor are performed using the `ForkJoinPool.commonPool()` executor.
### Non-async methods
When non-async methods are applied on a not yet completed `CompletionStage`, they are completed by
the thread which completes initial `CompletionStage`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-completion-thread }
In this example Scala `Future` is converted to `CompletionStage` just like Akka does.
The completion is delayed: we are calling `thenApply` multiple times on a not yet complete `CompletionStage`, then
complete the `Future`.
First `thenApply` is actually performed on `scala-java8-compat` instance and computational stage (lambda) execution
is delegated to default Java `thenApplyAsync` which is executed on `ForkJoinPool.commonPool()`.
Second and third `thenApply` methods are executed on Java 8 `CompletableFuture` instance which executes computational
stages on the thread which completed the first stage. It is never executed on a thread of Scala `Future` because
default `thenApply` breaks the chain and executes on `ForkJoinPool.commonPool()`.
In the next example `thenApply` methods are executed on an already completed `Future`/`CompletionStage`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-main-thread }
First `thenApply` is still executed on `ForkJoinPool.commonPool()` (because it is actually `thenApplyAsync`
which is always executed on global Java pool).
Then we wait for stages to complete so second and third `thenApply` are executed on completed `CompletionStage`,
and stages are executed on the current thread - the thread which called second and third `thenApply`.
### Async methods
As mentioned above, default *async* methods are always executed on `ForkJoinPool.commonPool()`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-async-default }
`CompletionStage` also has *async* methods which take `Executor` as a second parameter, just like `Future`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-async-executor }
This example is behaving like `Future`: every stage is executed on an explicitly specified `Executor`.
@@@ note
When in doubt, async methods with explicit executor should be used. Always async methods with a dedicated
executor/dispatcher for long-running or blocking computations, such as IO operations.
@@@
See also:
* [CompletionStage](https://docs.oracle.com/javase/8/jdocs/api/java/util/concurrent/CompletionStage.html)
* [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)
* [scala-java8-compat](https://github.com/scala/scala-java8-compat)

View file

@ -0,0 +1 @@
../scala/futures.md

View file

@ -6,14 +6,27 @@ In the Scala Standard Library, a [Future](http://en.wikipedia.org/wiki/Futures_a
used to retrieve the result of some concurrent operation. This result can be accessed synchronously (blocking) used to retrieve the result of some concurrent operation. This result can be accessed synchronously (blocking)
or asynchronously (non-blocking). or asynchronously (non-blocking).
@@@ div { .group-java }
To be able to use this from Java, Akka provides a java friendly interface
in `akka.dispatch.Futures`.
See also @ref:[Java 8 Compatibility](java8-compat.md) for Java compatibility.
@@@
## Execution Contexts ## Execution Contexts
In order to execute callbacks and operations, Futures need something called an `ExecutionContext`, In order to execute callbacks and operations, Futures need something called an `ExecutionContext`,
which is very similar to a `java.util.concurrent.Executor`. if you have an `ActorSystem` in scope, which is very similar to a `java.util.concurrent.Executor`. if you have an `ActorSystem` in scope,
it will use its default dispatcher as the `ExecutionContext`, or you can use the factory methods provided it will use its default dispatcher as the `ExecutionContext`, or you can use the factory methods provided
by the `ExecutionContext` companion object to wrap `Executors` and `ExecutorServices`, or even create your own. by the @scala[`ExecutionContext` companion object]@java[`ExecutionContexts` class] to wrap `Executors` and `ExecutorServices`, or even create your own.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #diy-execution-context } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #diy-execution-context }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports1 #diy-execution-context }
### Within Actors ### Within Actors
@ -22,24 +35,45 @@ dispatcher doubles as an `ExecutionContext`. If the nature of the Future
calls invoked by the actor matches or is compatible with the activities of that calls invoked by the actor matches or is compatible with the activities of that
actor (e.g. all CPU bound and no latency requirements), then it may be easiest actor (e.g. all CPU bound and no latency requirements), then it may be easiest
to reuse the dispatcher for running the Futures by importing to reuse the dispatcher for running the Futures by importing
`context.dispatcher`. @scala[`context.dispatcher`]@java[`getContext().dispatcher()`].
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #context-dispatcher } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #context-dispatcher }
## Use With Actors Java
: @@snip [ActorWithFuture.java]($code$/java/jdocs/future/ActorWithFuture.java) { #context-dispatcher }
There are generally two ways of getting a reply from an `Actor`: the first is by a sent message (`actor ! msg`), ## Use with Actors
which only works if the original sender was an `Actor`) and the second is through a `Future`.
Using an `Actor`'s `?` method to send a message will return a `Future`: There are generally two ways of getting a reply from an @scala[`Actor`]@java[`AbstractActor`]: the first is by a sent message (@scala[`actor ! msg`]@java[`actorRef.tell(msg, sender)`]),
which only works if the original sender was an @scala[`Actor`]@java[`AbstractActor`]) and the second is through a `Future`.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #ask-blocking } Using @scala[an `Actor`'s `?`]@java[the `ActorRef`'s `ask`] method to send a message will return a `Future`.
To wait for and retrieve the actual result the simplest method is:
This will cause the current thread to block and wait for the `Actor` to 'complete' the `Future` with it's reply. Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #ask-blocking }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports1 #ask-blocking }
This will cause the current thread to block and wait for the @scala[`Actor`]@java[`AbstractActor`] to 'complete' the `Future` with it's reply.
Blocking is discouraged though as it will cause performance problems. Blocking is discouraged though as it will cause performance problems.
The blocking operations are located in `Await.result` and `Await.ready` to make it easy to spot where blocking occurs. The blocking operations are located in `Await.result` and `Await.ready` to make it easy to spot where blocking occurs.
Alternatives to blocking are discussed further within this documentation. Also note that the `Future` returned by Alternatives to blocking are discussed further within this documentation. Also note that the `Future` returned by
an `Actor` is a `Future[Any]` since an `Actor` is dynamic. That is why the `asInstanceOf` is used in the above sample. an @scala[`Actor`]@java[`AbstractActor`] is a @scala[`Future[Any]`]@java[`Future<Object>`] since an @scala[`Actor`]@java[`AbstractActor`] is dynamic.
That is why the @scala[`asInstanceOf`]@java[cast to `String`] is used in the above sample.
@@@ warning
`Await.result` and `Await.ready` are provided for exceptional situations where you **must** block,
a good rule of thumb is to only use them if you know why you **must** block. For all other cases, use
asynchronous composition as described below.
@@@
@@@ div { .group-scala }
When using non-blocking it is better to use the `mapTo` method to safely try to cast a `Future` to an expected type: When using non-blocking it is better to use the `mapTo` method to safely try to cast a `Future` to an expected type:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #map-to } @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #map-to }
@ -47,34 +81,64 @@ When using non-blocking it is better to use the `mapTo` method to safely try to
The `mapTo` method will return a new `Future` that contains the result if the cast was successful, The `mapTo` method will return a new `Future` that contains the result if the cast was successful,
or a `ClassCastException` if not. Handling `Exception`s will be discussed further within this documentation. or a `ClassCastException` if not. Handling `Exception`s will be discussed further within this documentation.
@@@
To send the result of a `Future` to an `Actor`, you can use the `pipe` construct: To send the result of a `Future` to an `Actor`, you can use the `pipe` construct:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #pipe-to } scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #pipe-to }
java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #pipe-to }
## Use Directly ## Use Directly
A common use case within Akka is to have some computation performed concurrently without needing the extra utility of an `Actor`. A common use case within Akka is to have some computation performed concurrently without needing the extra utility of an @scala[`Actor`]@java[`AbstractActor`].
If you find yourself creating a pool of `Actor`s for the sole reason of performing a calculation in parallel, If you find yourself creating a pool of @scala[`Actor`s]@java[`AbstractActor`s] for the sole reason of performing a calculation in parallel,
there is an easier (and faster) way: there is an easier (and faster) way:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #future-eval } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #future-eval }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports2 #future-eval }
In the above code the block passed to `Future` will be executed by the default `Dispatcher`, In the above code the block passed to `Future` will be executed by the default `Dispatcher`,
with the return value of the block used to complete the `Future` (in this case, the result would be the string: "HelloWorld"). with the return value of the block used to complete the `Future` (in this case, the result would be the string: "HelloWorld").
Unlike a `Future` that is returned from an `Actor`, this `Future` is properly typed, Unlike a `Future` that is returned from an @scala[`Actor`]@java[`AbstractActor`], this `Future` is properly typed,
and we also avoid the overhead of managing an `Actor`. and we also avoid the overhead of managing an @scala[`Actor`]@java[`AbstractActor`].
You can also create already completed Futures using the `Future` companion, which can be either successes: You can also create already completed Futures using the @scala[`Future` companion]@java[`Futures` class], which can be either successes:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #successful } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #successful }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #successful }
Or failures: Or failures:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #failed } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #failed }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #failed }
It is also possible to create an empty `Promise`, to be filled later, and obtain the corresponding `Future`: It is also possible to create an empty `Promise`, to be filled later, and obtain the corresponding `Future`:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #promise } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #promise }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #promise }
@@@ div { .group-java }
For these examples `PrintResult` is defined as follows:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #print-result }
@@@
## Functional Futures ## Functional Futures
@ -83,19 +147,28 @@ These allow you to create 'pipelines' or 'streams' that the result will travel t
### Future is a Monad ### Future is a Monad
The first method for working with `Future` functionally is `map`. This method takes a `Function` The first method for working with `Future` functionally is `map`. This method takes a @scala[`Function`]@java[`Mapper`]
which performs some operation on the result of the `Future`, and returning a new result. which performs some operation on the result of the `Future`, and returning a new result.
The return value of the `map` method is another `Future` that will contain the new result: The return value of the `map` method is another `Future` that will contain the new result:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #map } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #map }
In this example we are joining two strings together within a `Future`. Instead of waiting for this to complete, Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports2 #map }
In this example we are joining two strings together within a `Future`. Instead of waiting for @scala[`this`]@java[`f1`] to complete,
we apply our function that calculates the length of the string using the `map` method. we apply our function that calculates the length of the string using the `map` method.
Now we have a second `Future` that will eventually contain an `Int`. Now we have a second `Future`, `f2`, that will eventually contain an @scala[`Int`]@java[`Integer`].
When our original `Future` completes, it will also apply our function and complete the second `Future` with its result. When our original `Future`, `f1`, completes, it will also apply our function and complete the second `Future` with its result.
When we finally get the result, it will contain the number 10. Our original `Future` still contains the When we finally get the result, it will contain the number 10. Our original `Future` still contains the
string "HelloWorld" and is unaffected by the `map`. string "HelloWorld" and is unaffected by the `map`.
Something to note when using these methods: passed work is always dispatched on the provided `ExecutionContext`. Even if
the `Future` has already been completed, when one of these methods is called.
@@@ div { .group-scala }
The `map` method is fine if we are modifying a single `Future`, The `map` method is fine if we are modifying a single `Future`,
but if 2 or more `Future`s are involved `map` will not allow you to combine them together: but if 2 or more `Future`s are involved `map` will not allow you to combine them together:
@ -123,8 +196,12 @@ each step of the for comprehension is run sequentially. This will happen on sepa
there isn't much benefit over running the calculations all within a single `Future`. there isn't much benefit over running the calculations all within a single `Future`.
The real benefit comes when the `Future`s are created first, and then combining them together. The real benefit comes when the `Future`s are created first, and then combining them together.
@@@
### Composing Futures ### Composing Futures
@@@ div { .group-scala }
The example for comprehension above is an example of composing `Future`s. The example for comprehension above is an example of composing `Future`s.
A common use case for this is combining the replies of several `Actor`s into a single calculation A common use case for this is combining the replies of several `Actor`s into a single calculation
without resorting to calling `Await.result` or `Await.ready` to block for each result. without resorting to calling `Await.result` or `Await.ready` to block for each result.
@ -132,14 +209,6 @@ First an example of using `Await.result`:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #composing-wrong } @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #composing-wrong }
@@@ warning
`Await.result` and `Await.ready` are provided for exceptional situations where you **must** block,
a good rule of thumb is to only use them if you know why you **must** block. For all other cases, use
asynchronous composition as described below.
@@@
Here we wait for the results from the first 2 `Actor`s before sending that result to the third `Actor`. Here we wait for the results from the first 2 `Actor`s before sending that result to the third `Actor`.
We called `Await.result` 3 times, which caused our little program to block 3 times before getting our final result. We called `Await.result` 3 times, which caused our little program to block 3 times before getting our final result.
Now compare that to this example: Now compare that to this example:
@ -155,16 +224,36 @@ The `sequence` and `traverse` helper methods can make it easier to handle more c
Both of these methods are ways of turning, for a subclass `T` of `Traversable`, `T[Future[A]]` into a `Future[T[A]]`. Both of these methods are ways of turning, for a subclass `T` of `Traversable`, `T[Future[A]]` into a `Future[T[A]]`.
For example: For example:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #sequence-ask } @@@
To better explain what happened in the example, `Future.sequence` is taking the `List[Future[Int]]` @@@ div { .group-java }
and turning it into a `Future[List[Int]]`. We can then use `map` to work with the `List[Int]` directly,
and we find the sum of the `List`.
The `traverse` method is similar to `sequence`, but it takes a `T[A]` and a function `A => Future[B]` to return a `Future[T[B]]`, It is very often desirable to be able to combine different Futures with each other,
where `T` is again a subclass of Traversable. For example, to use `traverse` to sum the first 100 odd numbers: below are some examples on how that can be done in a non-blocking fashion.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #traverse } @@@
Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #sequence-ask }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports3 #sequence }
To better explain what happened in the example, `Future.sequence` is taking the @scala[`List[Future[Int]]`]@java[`Iterable<Future<Integer>>`]
and turning it into a @scala[`Future[List[Int]]`]@java[`Future<Iterable<Integer>>`]. We can then use `map` to work with the @scala[`List[Int]`]@java[`Iterable<Integer>`] directly,
and we aggregate the sum of the @scala[`List`]@java[`Iterable`].
The `traverse` method is similar to `sequence`, but it takes a sequence of `A` and applies a function @scala[`A => Future[B]`]@java[from `A` to `Future<B>`]
@scala[to return a `Future[T[B]]` where `T` is again a subclass of Traversable. For example, to use `traverse` to sum the first 100 odd numbers:]
@java[and returns a `Future<Iterable<B>>`, enabling parallel map over the sequence, if you use `Futures.future` to create the `Future`.]
Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #traverse }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports4 #traverse }
@@@ div { .group-scala }
This is the same result as this example: This is the same result as this example:
@ -172,12 +261,19 @@ This is the same result as this example:
But it may be faster to use `traverse` as it doesn't have to create an intermediate `List[Future[Int]]`. But it may be faster to use `traverse` as it doesn't have to create an intermediate `List[Future[Int]]`.
Then there's a method that's called `fold` that takes a start-value, a sequence of `Future`s and a function @@@
from the type of the start-value and the type of the futures and returns something with the same type as the start-value,
and then applies the function to all elements in the sequence of futures, asynchronously,
the execution will start when the last of the Futures is completed.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #fold } Then there's a method that's called `fold` that takes a start-value,
a sequence of `Future`s and a function from the type of the start-value, a timeout,
and the type of the futures and returns something with the same type as the start-value,
and then applies the function to all elements in the sequence of futures, non-blockingly,
the execution will be started when the last of the Futures is completed.
Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #fold }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports5 #fold }
That's all it takes! That's all it takes!
@ -185,7 +281,11 @@ If the sequence passed to `fold` is empty, it will return the start-value, in th
In some cases you don't have a start-value and you're able to use the value of the first completing `Future` in the sequence In some cases you don't have a start-value and you're able to use the value of the first completing `Future` in the sequence
as the start-value, you can use `reduce`, it works like this: as the start-value, you can use `reduce`, it works like this:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #reduce } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #reduce }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports6 #reduce }
Same as with `fold`, the execution will be done asynchronously when the last of the `Future` is completed, Same as with `fold`, the execution will be done asynchronously when the last of the `Future` is completed,
you can also parallelize it by chunking your futures into sub-sequences and reduce them, and then reduce the reduced results again. you can also parallelize it by chunking your futures into sub-sequences and reduce them, and then reduce the reduced results again.
@ -193,13 +293,27 @@ you can also parallelize it by chunking your futures into sub-sequences and redu
## Callbacks ## Callbacks
Sometimes you just want to listen to a `Future` being completed, and react to that not by creating a new `Future`, but by side-effecting. Sometimes you just want to listen to a `Future` being completed, and react to that not by creating a new `Future`, but by side-effecting.
For this Scala supports `onComplete`, `onSuccess` and `onFailure`, of which the last two are specializations of the first. For this `Future` supports `onComplete`, `onSuccess` and `onFailure`, of which the last two are specializations of the first.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #onSuccess } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #onSuccess }
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #onFailure } Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #onSuccess }
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #onComplete }
Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #onFailure }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #onFailure }
Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #onComplete }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #onComplete }
## Define Ordering ## Define Ordering
@ -209,31 +323,47 @@ But there's a solution and it's name is `andThen`. It creates a new `Future` wit
the specified callback, a `Future` that will have the same result as the `Future` it's called on, the specified callback, a `Future` that will have the same result as the `Future` it's called on,
which allows for ordering like in the following sample: which allows for ordering like in the following sample:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #and-then } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #and-then }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #and-then }
## Auxiliary Methods ## Auxiliary Methods
`Future` `fallbackTo` combines 2 Futures into a new `Future`, and will hold the successful value of the second `Future` `Future` `fallbackTo` combines 2 Futures into a new `Future`, and will hold the successful value of the second `Future`
if the first `Future` fails. if the first `Future` fails.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #fallback-to } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #fallback-to }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #fallback-to }
You can also combine two Futures into a new `Future` that will hold a tuple of the two Futures successful results, You can also combine two Futures into a new `Future` that will hold a tuple of the two Futures successful results,
using the `zip` operation. using the `zip` operation.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #zip } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #zip }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #zip }
## Exceptions ## Exceptions
Since the result of a `Future` is created concurrently to the rest of the program, exceptions must be handled differently. Since the result of a `Future` is created concurrently to the rest of the program, exceptions must be handled differently.
It doesn't matter if an `Actor` or the dispatcher is completing the `Future`, It doesn't matter if an @scala[`Actor`]@java[`AbstractActor`] or the dispatcher is completing the `Future`,
if an `Exception` is caught the `Future` will contain it instead of a valid result. if an `Exception` is caught the `Future` will contain it instead of a valid result.
If a `Future` does contain an `Exception`, calling `Await.result` will cause it to be thrown again so it can be handled properly. If a `Future` does contain an `Exception`, calling `Await.result` will cause it to be thrown again so it can be handled properly.
It is also possible to handle an `Exception` by returning a different result. It is also possible to handle an `Exception` by returning a different result.
This is done with the `recover` method. For example: This is done with the `recover` method. For example:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #recover } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #recover }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #recover }
In this example, if the actor replied with a `akka.actor.Status.Failure` containing the `ArithmeticException`, In this example, if the actor replied with a `akka.actor.Status.Failure` containing the `ArithmeticException`,
our `Future` would have a result of 0. The `recover` method works very similarly to the standard try/catch blocks, our `Future` would have a result of 0. The `recover` method works very similarly to the standard try/catch blocks,
@ -243,10 +373,116 @@ it will behave as if we hadn't used the `recover` method.
You can also use the `recoverWith` method, which has the same relationship to `recover` as `flatMap` has to `map`, You can also use the `recoverWith` method, which has the same relationship to `recover` as `flatMap` has to `map`,
and is use like this: and is use like this:
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #try-recover } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #try-recover }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #try-recover }
## After ## After
`akka.pattern.after` makes it easy to complete a `Future` with a value or exception after a timeout. `akka.pattern.after` makes it easy to complete a `Future` with a value or exception after a timeout.
@@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #after } Scala
: @@snip [FutureDocSpec.scala]($code$/scala/docs/future/FutureDocSpec.scala) { #after }
Java
: @@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #imports7 #after }
@@@ div { .group-java }
## Java 8, CompletionStage and CompletableFuture
Starting with Akka 2.4.2 we have begun to introduce Java 8 `java.util.concurrent.CompletionStage` in Java APIs.
It's a `scala.concurrent.Future` counterpart in Java; conversion from `scala.concurrent.Future` is done using
`scala-java8-compat` library.
Unlike `scala.concurrent.Future` which has async methods only, `CompletionStage` has *async* and *non-async* methods.
The `scala-java8-compat` library returns its own implementation of `CompletionStage` which delegates all *non-async*
methods to their *async* counterparts. The implementation extends standard Java `CompletableFuture`.
Java 8 `CompletableFuture` creates a new instance of `CompletableFuture` for any new stage,
which means `scala-java8-compat` implementation is not used after the first mapping method.
@@@
@@@ note { .group-java }
After adding any additional computation stage to `CompletionStage` returned by `scala-java8-compat`
(e.g. `CompletionStage` instances returned by Akka) it falls back to standard behaviour of Java `CompletableFuture`.
@@@
@@@ div { .group-java }
Actions supplied for dependent completions of *non-async* methods may be performed by the thread
that completes the current `CompletableFuture`, or by any other caller of a completion method.
All *async* methods without an explicit Executor are performed using the `ForkJoinPool.commonPool()` executor.
@@@
@@@ div { .group-java }
### Non-async methods
When non-async methods are applied on a not yet completed `CompletionStage`, they are completed by
the thread which completes initial `CompletionStage`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-completion-thread }
In this example Scala `Future` is converted to `CompletionStage` just like Akka does.
The completion is delayed: we are calling `thenApply` multiple times on a not yet complete `CompletionStage`, then
complete the `Future`.
First `thenApply` is actually performed on `scala-java8-compat` instance and computational stage (lambda) execution
is delegated to default Java `thenApplyAsync` which is executed on `ForkJoinPool.commonPool()`.
Second and third `thenApply` methods are executed on Java 8 `CompletableFuture` instance which executes computational
stages on the thread which completed the first stage. It is never executed on a thread of Scala `Future` because
default `thenApply` breaks the chain and executes on `ForkJoinPool.commonPool()`.
In the next example `thenApply` methods are executed on an already completed `Future`/`CompletionStage`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-main-thread }
First `thenApply` is still executed on `ForkJoinPool.commonPool()` (because it is actually `thenApplyAsync`
which is always executed on global Java pool).
Then we wait for stages to complete so second and third `thenApply` are executed on completed `CompletionStage`,
and stages are executed on the current thread - the thread which called second and third `thenApply`.
@@@
@@@ div { .group-java }
### Async methods
As mentioned above, default *async* methods are always executed on `ForkJoinPool.commonPool()`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-async-default }
`CompletionStage` also has *async* methods which take `Executor` as a second parameter, just like `Future`:
@@snip [FutureDocTest.java]($code$/java/jdocs/future/FutureDocTest.java) { #apply-async-executor }
This example is behaving like `Future`: every stage is executed on an explicitly specified `Executor`.
@@@
@@@ note { .group-java }
When in doubt, async methods with explicit executor should be used. Always async methods with a dedicated
executor/dispatcher for long-running or blocking computations, such as IO operations.
@@@
@@@ div { .group-java }
See also:
* [CompletionStage](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html)
* [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)
* [scala-java8-compat](https://github.com/scala/scala-java8-compat)
@@@

View file

@ -0,0 +1,17 @@
package jdocs.future;
//#context-dispatcher
import akka.actor.AbstractActor;
import akka.dispatch.Futures;
public class ActorWithFuture extends AbstractActor {
ActorWithFuture(){
Futures.future(() -> "hello", getContext().dispatcher());
}
@Override
public Receive createReceive() {
return AbstractActor.emptyBehavior();
}
}
// #context-dispatcher

View file

@ -11,6 +11,8 @@ import scala.concurrent.Future;
import scala.concurrent.Await; import scala.concurrent.Await;
import scala.concurrent.Promise; import scala.concurrent.Promise;
import akka.util.Timeout; import akka.util.Timeout;
//#imports1 //#imports1
//#imports2 //#imports2
@ -19,27 +21,39 @@ import akka.japi.Function;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import static akka.dispatch.Futures.future; import static akka.dispatch.Futures.future;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
//#imports2 //#imports2
//#imports3 //#imports3
import static akka.dispatch.Futures.sequence; import static akka.dispatch.Futures.sequence;
//#imports3 //#imports3
//#imports4 //#imports4
import static akka.dispatch.Futures.traverse; import static akka.dispatch.Futures.traverse;
//#imports4 //#imports4
//#imports5 //#imports5
import akka.japi.Function2; import akka.japi.Function2;
import static akka.dispatch.Futures.fold; import static akka.dispatch.Futures.fold;
//#imports5 //#imports5
//#imports6 //#imports6
import static akka.dispatch.Futures.reduce; import static akka.dispatch.Futures.reduce;
//#imports6 //#imports6
//#imports7 //#imports7
import static akka.pattern.Patterns.after; import static akka.pattern.Patterns.after;
import java.util.Arrays; import java.util.Arrays;
//#imports7 //#imports7