Skip to content
Peter Nerg edited this page Jul 18, 2015 · 26 revisions

Future/Promise

The Future/Promise concept is the way to separate the execution/job side (Promise) from the client/receiver side (Future).
The following simple example illustrates the concept.
We have a method that returns a Future that some time in the future will hold a string containing the echoed name provided to the method.
The pseudo-code pauseRandomTime() is to give a feel that the job takes some time to execute.

public Future<String> echoName(String name) {
    Promise<String> promise = Promise.apply();
    new Thread() {
        public void run() {
            //illustrates some execution time            
            pauseRandomTime(); 
            //the actual response
            promise.success("Hello " + name);
        };
    }.run();
    return promise.future();
}

##Promise The Promise is the promise to deliver a value at some time in the future.
This is the handle the actual computation side of of the job uses. Once a job is finished it will report the outcome to the Promise which in turn relays it to the Future the client/application is monitoring.
A promise can be fulfilled either by invoking success or failure but not both. Nor can success/failure be invoked twice.
The principle is that a Promise will deliver exactly one successful or failure response.
The successful response is of any type whilst the failure is expected to be of type (or subclass of) Throwable.

##Future The Future is the bearer of a value-to-be, an execution yet to be finished.
The purpose is to have a placeholder for a value from an asynchronous computation.
The Future is designed for a single value response, if you are looking for a mechanism to provide 0..n amount of responses I'd suggest you look at the Observable mechanism provided in the reactive pattern.
One good implementation for this is RxJava.
In contrast to the java.util.concurrent.Future provided in the SDK this Future is designed for non-blocking operation. The idea is to let the user/developer decide whether to block for an answer to have the answer passed as an event via one of the several subscription possibilities.
##Examples

###Asynchronous/event based responses As mentioned the difference to the Future provided in the Java SDK this implementation is by nature non-blocking.
The way to receive the responses is via a series of event handlers.
One can choose which types of responses to receive notification for: successful, failure or a combination of both. Let's for the sake of examples assume this Future:

Future<String> future = ...

To receive a successful response one installs a success listener:

future.onSuccess(s -> System.out.println(s));

To receive a failure response one installs a failure listener:

future.onFailure(ex -> System.out.println(ex.getMessage()));

Of course both listeners can be installed on the same Future. In fact one can install multiple listeners of the same type to the Future. Thus multiple clients can receive notifications from the same Future instance.

Should one want to get notified of either outcome successful/failure then there is the possibility to install a handler that listens to both outcomes.
Using the onComplete you'll get a Try handed to you letting you decide whether it's a success/failure.

future.onComplete(t -> System.out.println(t.isSuccess()));

###Blocking responses For convenience the Future provides a blocking method allowing the user to block for the response.
Whilst this is against the reactive principles it might sometimes be necessary if the rest of your application anyways is synchronous by nature.
The method result allows you to block for a result for a provided duration.
Any successful result is produced as a return whilst failure responses are thrown as exceptions.

Future<String> future = ...
String result = future.result(5, TimeUnit.SECONDS);

###Mapping Futures One intriguing concept is to map a Future to some other Future.
Now this may seem completely out of place but let's take this simple example where we have a Future of the type String which we intend to make to a Future of numerical type.

Future<String> future = ...
//our mapping function simply takes the length of the string
Future<Integer> mapped =  = future..map(s -> s.length());
mapped.onSuccess(length -> System.out.println("The string was this long:"+length));

There's still no data in the Future until it has been completed but when the original Future is completed with a String our mapped one is immediately completed with an Integer representing the length of the string.

Clone this wiki locally