concept Future in category java

This is an excerpt from Manning's book Modern Java in Action: Lambdas, streams, reactive and functional programming.
You may be familiar with the ExecutorService abstraction that was introduced in Java 5. The ExecutorService interface decouples how tasks are submitted and executed. What’s useful in comparison to using threads and Runnable is that by using an Executor-Service you can send a task to a pool of threads and have its result stored in a Future. Don’t worry if this is unfamiliar, we will revisit this topic in later chapters when we discuss concurrency in more detail. For now, all you need to know is that the Callable interface is used to model a task that returns a result. You can see it as an upgraded Runnable:
The Future interface was introduced in Java 5 to model a result made available at some point in the future. A query to a remote service won’t be available immediately when the caller makes the request, for example. The Future interface models an asynchronous computation and provides a reference to its result that becomes available when the computation itself is completed. Triggering a potentially time-consuming action inside a Future allows the caller Thread to continue doing useful work instead of waiting for the operation’s result. You can think of this process as being like taking a bag of clothes to your favorite dry cleaner. The cleaner gives you a receipt to tell you when your clothes will be cleaned (a Future); in the meantime, you can do some other activities. Another advantage of Future is that it’s friendlier to work with than lower-level Threads. To work with a Future, you typically have to wrap the time-consuming operation inside a Callable object and submit it to an ExecutorService. The following listing shows an example written before Java 8.
Listing 16.1. Executing a long-lasting operation asynchronously in a Future
ExecutorService executor = Executors.newCachedThreadPool(); #1 Future<Double> future = executor.submit(new Callable<Double>() { #2 public Double call() { return doSomeLongComputation(); #3 }}); doSomethingElse(); #4 try { Double result = future.get(1, TimeUnit.SECONDS); #5 } catch (ExecutionException ee) { // the computation threw an exception } catch (InterruptedException ie) { // the current thread was interrupted while waiting } catch (TimeoutException te) { // the timeout expired before the Future completion }As depicted in figure 16.1, this style of programming allows your thread to perform some other tasks while the long-lasting operation is executed concurrently in a separate thread provided by the ExecutorService. Then, when you can’t do any other meaningful work without having the result of that asynchronous operation, you can retrieve it from the Future by invoking its get method. This method immediately returns the result of the operation if it’s already completed or blocks your thread, waiting for its result to be available.
Note the problem with this scenario. What if the long operation never returns? To handle this possibility, it’s almost always a good idea to use the two-argument version of get, which takes a timeout specifying the maximum time (along with its time unit) that your thread is willing to wait for the Future’s result (as in listing 16.1). The zero-argument version of get would instead wait indefinitely.
As we mentioned in the introduction of this chapter, the java.util.concurrent.Future interface was introduced in Java 5 to represent the result of an asynchronous computation. (That is, the caller thread is allowed to proceed without blocking.) A Future is a handle for a value that isn’t available yet but that can be retrieved by invoking its get method after its computation finally terminates. As a result, the getPriceAsync method can return immediately, giving the caller thread a chance to perform other useful computations in the meantime. The Java 8 CompletableFuture class gives you various possibilities to implement this method easily, as shown in the following listing.
Listing 16.4. Implementing the getPriceAsync method
public Future<Double> getPriceAsync(String product) { CompletableFuture<Double> futurePrice = new CompletableFuture<>(); #1 new Thread( () -> { double price = calculatePrice(product); #2 futurePrice.complete(price); #3 }).start(); return futurePrice; #4 }Here, you create an instance of CompletableFuture, representing an asynchronous computation and containing a result when it becomes available. Then you fork a different Thread that will perform the actual price calculation and return the Future instance without waiting for that long-lasting calculation to terminate. When the price of the requested product is finally available, you can complete the CompletableFuture, using its complete method to set the value. This feature also explains the name of this Java 8 implementation of Future. A client of this API can invoke it, as shown in the next listing.
Listing 16.5. Using an asynchronous API
Shop shop = new Shop("BestShop"); long start = System.nanoTime(); Future<Double> futurePrice = shop.getPriceAsync("my favorite product"); #1 long invocationTime = ((System.nanoTime() - start) / 1_000_000); System.out.println("Invocation returned after " + invocationTime + " msecs"); // Do some more tasks, like querying other shops doSomethingElse(); // while the price of the product is being calculated try { double price = futurePrice.get(); #2 System.out.printf("Price is %.2f%n", price); } catch (Exception e) { throw new RuntimeException(e); } long retrievalTime = ((System.nanoTime() - start) / 1_000_000); System.out.println("Price returned after " + retrievalTime + " msecs");As you can see, the client asks the shop to get the price of a certain product. Because the shop provides an asynchronous API, this invocation almost immediately returns the Future, through which the client can retrieve the product’s price later. Then the client can perform other tasks, such as querying other shops, instead of remaining blocked, waiting for the first shop to produce the requested result. Later, when the client can do no other meaningful jobs without having the product price, it can invoke get on the Future. By doing so, the client unwraps the value contained in the Future (if the asynchronous task is finished) or remains blocked until that value is available. The output produced by the code in listing 16.5 could be something like this:
Invocation returned after 43 msecs Price is 123.26 Price returned after 1045 msecsYou can see that the invocation of the getPriceAsync method returns far sooner than when the price calculation eventually finishes. In section 16.4, you learn that it’s also possible for the client to avoid any risk of being blocked. Instead, the client can be notified when the Future is complete and can execute a callback code, defined through a lambda expression or a method reference, only when the result of the computation is available. For now, we’ll address another problem: how to manage an error during the execution of the asynchronous task.
The last two examples in listings 16.16 and 16.17 clearly show one of the biggest advantages of CompletableFutures over the other pre-Java 8 Future implementations. CompletableFutures use lambda expressions to provide a declarative API. This API allows you to easily combine and compose various synchronous and asynchronous tasks to perform a complex operation in the most effective way. To get a more tangible idea of the code-readability benefits of CompletableFuture, try to obtain the result of listing 16.17 purely in Java 7. The next listing shows you how.
Listing 16.18. Combining two Futures in Java 7
ExecutorService executor = Executors.newCachedThreadPool(); #1 final Future<Double> futureRate = executor.submit(new Callable<Double>() { public Double call() { return exchangeService.getRate(Money.EUR, Money.USD); #2 }}); Future<Double> futurePriceInUSD = executor.submit(new Callable<Double>() { public Double call() { double priceInEUR = shop.getPrice(product); #3 return priceInEUR * futureRate.get(); #4 }});In listing 16.18, you create a first Future, submitting a Callable to an Executor querying an external service to find the exchange rate between EUR and USD. Then you create a second Future, retrieving the price in EUR of the requested product for a given shop. Finally, as you did in listing 16.17, you multiply the exchange rate by the price in the same future that also queried the shop to retrieve the price in EUR. Note that using thenCombineAsync instead of thenCombine in listing 16.17 would have been equivalent to performing the price by rate multiplication in a third Future in listing 16.18. The difference between these two implementations may seem to be small only because you’re combining two Futures.

This is an excerpt from Manning's book Java 8 in Action: Lambdas, streams, and functional-style programming.
Conversely, when dealing with concurrency instead of parallelism, or when your main goal is to perform several loosely related tasks on the same CPUs, keeping their cores as busy as possible to maximize the throughput of your application, what you really want to achieve is to avoid blocking a thread and wasting its computational resources while waiting, potentially for quite a while, for a result from a remote service or from interrogating a database. As you’ll see in this chapter, the Future interface and particularly its new CompletableFuture implementation are your best tools in such circumstances. Figure 11.2 illustrates the difference between parallelism and concurrency.
The Future interface was introduced in Java 5 to model a result made available at some point in the future. It models an asynchronous computation and provides a reference to its result that will be available when the computation itself is completed. Triggering a potentially time-consuming action inside a Future allows the caller Thread to continue doing useful work instead of just waiting for the operation’s result. You can think of it as taking a bag of clothes to your favorite dry cleaner. They will give you a receipt to tell you when your clothes are cleaned (a Future). In the meantime, you can do some other activities. Another advantage of Future is that it’s friendlier to work with than lower-level Threads. To work with a Future, you typically have to wrap the time-consuming operation inside a Callable object and submit it to an Executor-Service. The following listing shows an example written before Java 8.
As depicted in figure 11.3, this style of programming allows your thread to perform some other tasks while the long-lasting operation is executed concurrently in a separate thread provided by the ExecutorService. Then, when you can’t do any other meaningful work without having the result of that asynchronous operation, you can retrieve it from the Future by invoking its get method. This method immediately returns the result of the operation if it’s already completed or blocks your thread, waiting for its result to be available.
Can you think of a problem with this scenario? What if the long operation never returns? To handle this possibility, even though there also exists a get method that doesn’t take a parameter, it’s almost always a good idea to use its overloaded version, accepting a timeout defining the maximum time your thread has to wait for the Future’s result, as you did in listing 11.1, instead of waiting indefinitely.
The last two examples in listings 11.16 and 11.17 clearly show one of the biggest advantages of CompletableFutures over the other pre-Java 8 Future implementations. CompletableFutures use lambda expressions to provide a declarative API that offers the possibility of easily defining a recipe that combines and composes different synchronous and asynchronous tasks to perform a complex operation in the most effective way. To get a more tangible idea of the code readability benefits of Completable-Future, try to obtain the same result of listing 11.17 purely in Java 7. Listing 11.18 shows you how to do it.
In listing 11.18, you create a first Future, submitting a Callable to an Executor querying an external service to find the exchange rate between EUR and USD. Then you create a second Future, retrieving the price in EUR of the requested product for a given shop. Finally, as you did in listing 11.17, you multiply the exchange rate by the price in the same future that also queried the shop to retrieve the price in EUR. Note that using thenCombineAsync instead of thenCombine in listing 11.17 would have been equivalent to performing the price by rate multiplication in a third Future in listing 11.18. The difference between these two implementations might seem small, but this is because you’re just combining two Futures. Listings 11.19 and 11.20 show how easy it is to create a pipeline that mixes synchronous and asynchronous operations, and the advantages of this declarative style are more evident when the number of tasks to be performed and results to be combined increases.