A Future.

JDK 5 introduced the Future pattern. The Future interface is an implementation of the Java multi-threaded Future pattern in the java.util.Concurrent package that can be used to perform asynchronous computations.

The Future pattern is a common design pattern in multithreaded design. The Future mode can be interpreted as: I have a task, I submit it to a Future, and the Future completes the task for me. In the meantime, I can do whatever I want. After a period of time, I can extract the results from Future.

The Future’s interface is simple, with just five methods.

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled(a);

    boolean isDone(a);

    V get(a) throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}Copy the code

The Future interface method is described as follows:

  • Boolean Cancel (Boolean mayInterruptIfRunning) Cancles the execution of a task. Parameter specifies whether to interrupt the task immediately or wait for the task to finish
  • Boolean isCancelled () whether the task has been cancelled. True is returned if the task isCancelled before normal completion
  • Boolean isDone () whether the task has been completed. Note that true will be returned if the task terminates normally, exceptions, or cancellations
  • V get () throws InterruptedException, ExecutionException Wait until the task is executed and obtain the V result. InterruptedException if the thread is interrupted, ExecutionException if the task is executed, and CancellationException if the task is cancelled
  • V get (long Timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException Set the timeout period. The timeout argument specifies the timeout period, and uint specifies the unit of time, as defined in the enumeration class TimeUnit. If the timeout is counted, a TimeoutException is thrown

In general, we use a Callable with a Future, executing the Callable through the Submit method of the ExecutorService, and returning the Future.

        ExecutorService executor = Executors.newCachedThreadPool();

        Future<String> future = executor.submit(() -> { //Lambda is a callable that executes immediately upon submission, returning a FutureTask instance
            System.out.println("running task");
            Thread.sleep(10000);
            return "return task";
        });

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        System.out.println("do something else");  // The previous Callable is running in another thread and can do something else

        try {
            System.out.println(future.get());  // Wait for the result of the future execution and print it when it is finished
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {

        } finally {
            executor.shutdown();
        }Copy the code

Get (long Timeout, TimeUnit Unit) is more recommended than future.get(). Setting the timeout prevents an application from waiting indefinitely for the result of a future.

Introduction to CompletableFuture

2.1 Disadvantages of the Future model

  • A Future can fulfill the need to retrieve the results of an asynchronous execution, but it does not provide a mechanism for notification of when the Future is finished.

  • Either block and wait for the future to return the result at future.get(), which becomes synchronous again. Or use isDone() to poll whether the Future is finished, which is CPU intensive.

2.2 introduce CompletableFuture

Netty and Guava respectively extend Java’s Future interface to facilitate asynchronous programming.

The new CompletableFuture class in Java 8 takes all the features of Google Guava’s ListenableFuture and SettableFuture, and provides other powerful features that give Java a complete non-blocking programming model: Futures, promises, and callbacks (prior to Java8, there were only callbackless futures).

The CompletableFuture can execute the callback in a different thread from the task, or it can execute the callback as a continuing synchronization function in the same thread as the task. It avoids the biggest problem with traditional callbacks, which is the ability to separate the flow of control into different event handlers.

CompletableFuture makes up for the shortcomings of the Future model. When an asynchronous task is complete and you need to continue with its results, there is no need to wait. The result of the previous asynchronous processing can be handed over to another asynchronous event processing thread directly via thenAccept, thenApply, thenCompose, etc.

Iii. CompletableFuture feature

3.1 Static factory method for CompletableFuture

The method name describe
runAsync(Runnable runnable) Use ForkJoinPool.commonPool() as its thread pool to execute asynchronous code.
runAsync(Runnable runnable, Executor executor) Executes asynchronous code using the specified Thread pool.
supplyAsync(Supplier<U> supplier) Async code is executed using ForkJoinPool.commonPool() as its thread pool. Async operations have a return value
supplyAsync(Supplier<U> supplier, Executor executor) Executes asynchronous code using the specified Thread pool. An asynchronous operation has a return value

The difference between runAsync and supplyAsync is that runAsync returns a CompletableFuture with no return value.

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("Hello");
        });

        try {
            future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("CompletableFuture");Copy the code

Whereas the supplyAsync returns a CompletableFuture from the return value, the following code prints the return value of the Future.

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("CompletableFuture");Copy the code

3.2 Completable

The method name describe
complete(T t) Complete the asynchronous execution and return the result of the Future
completeExceptionally(Throwable ex) Abnormal end of asynchronous execution

Future.get () will block while waiting for the result of the execution. Calling complete(T T) will execute immediately.

        CompletableFuture<String> future  = CompletableFuture.supplyAsync(() -> "Hello");

        future.complete("World");

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }Copy the code

Execution result:

WorldCopy the code

You can see that the Future call complete(T T) executes immediately. However, complete(T T) can only be called once, and subsequent repeated calls are invalidated.

Calling complete(T T) will be invalid if the Future has completed and returns a result.

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        future.complete("World");

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }Copy the code

Execution result:

HelloCopy the code

If completeExceptionally(Throwable ex) is used, then an exception is thrown instead of a successful result.

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

        future.completeExceptionally(new Exception());

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }Copy the code

Execution result:

java.util.concurrent.ExecutionException: java.lang.Exception
...Copy the code