Merge paradox/scala/futures.md and java/futures.md (#23397)
This commit is contained in:
parent
e5249c69b6
commit
e0692b5e93
4 changed files with 326 additions and 354 deletions
|
|
@ -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)
|
|
||||||
1
akka-docs/src/main/paradox/java/futures.md
Symbolic link
1
akka-docs/src/main/paradox/java/futures.md
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../scala/futures.md
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
|
||||||
17
akka-docs/src/test/java/jdocs/future/ActorWithFuture.java
Normal file
17
akka-docs/src/test/java/jdocs/future/ActorWithFuture.java
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue