In JDK1.5, there are implementations of Future and Callable, which can be used to retrieve results in a blocking manner. If you want to retrieve results asynchronously, you will usually retrieve results in a polling manner, as follows:

// Future<String> Future = executor.submit(() -> {Thread.sleep(2000); return "hello world"; }); If (future.isDone()) {System.out.println(future.get()); if (future.isDone()) {System.out.println(future.get()); break; }}

It seems from the above form that polling consumes CPU resources and can’t get the results in a timely manner. So to achieve true asynchrony, this is not enough, and we see asynchronous programming everywhere in Netty

ChannelFuture f = serverBootstrap.bind(port).sync(); f.addListener(new GenericFutureListener<Future<? super Void>>() { @Override public void operationComplete(Future<? super Void> future) throws Exception { System.out.println("complete"); }});
And completableFuture in JDK1.8 provides us with asynchronous functional programming. CompletableFuture provides a very powerful extension function of Future, which can help us simplify the complexity of asynchronous programming and provide the ability of functional programming. Calculated results can be processed as callbacks, and methods for converting and composing completableFuture are provided.
  1. CompletableFuture provides four static methods to create a completableFuture object:

Asynsc is asynchronous, and supplyAsync differs from runyasync in that async returns a result, which is void. The second function uses our own thread pool as its second argument, otherwise it uses the default forkJoinPool.com monPool() as its thread pool. The Supplier is a functional interface that stands for a producer, passes in 0 arguments and returns a result (see my other article for more details).

CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); System.out.println(future.get()); // Blocked fetching results ""
  1. Proactively calculate the following four methods to obtain the results

GetNow is a bit special in that it returns the result if it has already been computed or throws an exception, otherwise it returns the given value of ValueIBAbsent. The difference between join() and get() is that join() returns the result of a calculation or throws an unchecked exception, while get() returns a concrete exception.

Active trigger calculation.



The above method means that when the call completablefuture.get () is blocked, then the method closes the block and get() gets the value set.

public static CompletableFuture<Integer> compute () { final CompletableFuture<Integer> future = new CompletableFuture<>(); return future; } public static void main (String[]args) throws Exception { final CompletableFuture<Integer> f = compute(); class Client extends Thread { CompletableFuture<Integer> f; Client(String threadName, CompletableFuture<Integer> f) { super(threadName); this.f = f; } @Override public void run() { try { System.out.println(this.getName() + ": " + f.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } new Client("Client1", f).start(); new Client("Client2", f).start(); System.out.println("waiting"); // Set future.get () to get f.plete (100); / / in the form of abnormal trigger calculation / / f.com pleteExceptionally (new Exception ()); Thread.sleep(1000); }
  1. The above four methods are fired at the end of the computation phase. The BiConsumer takes two parameters, one for the return value of the computation, and the other for an exception. A method that does not end in Async means that the Action is executed using the same thread, and Async may be executed using another thread (or selected for execution by the same thread if the same thread pool is used).
 future.whenCompleteAsync((v, e) -> {
            System.out.println("return value:" + v + "  exception:" + e);
        });

handle()

Unlike whenComplete(), this function returns a completableFuture not the value returned by the original completableFuture, but the value returned by the biFunction.

  1. When the calculation is complete, a series of theApply can be followed to complete the conversion of values.

They differ from the Handle method in that the Handle method handles normal computed values and exceptions, so it can mask exceptions and prevent them from being thrown further. The thenApply method is only used to handle normal values, so an exception is thrown whenever it occurs.

CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{ return "hello world"; }); CompletableFuture<String> future3 = future.thenApply((element)->{ return element+" addPart"; }).thenApply((element)->{ return element+" addTwoPart"; }); System.out.println(future3.get()); //hello world addPart addTwoPart
  1. The Consumer of a CompletableFuture only consumes the result of the CompletableFuture without returning a value, that is, the last CompletableFuture is void.
// Enter the result of the original CompletableFuture. CompletableFuture future4 = future.thenAccept((e)->{ System.out.println("without return value"); }); future4.get();

The thenAcceptBoth method is used to combine two completablefutures where one CompletableFuture waits for the result of the other CompletableFuture.

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { return "hello world"; }); CompletableFuture future5 = future.thenAcceptBoth(CompletableFuture.completedFuture("compose"), (x, y) -> System.out.println(x + y)); //hello world compose
  1. The Either and ALL thenAcceptBoth are when both completablefutures have been computed, and the method applyToEither that we’ll look at next is when Either CompletableFuture has been computed.
Random rand = new Random(); CompletableFuture<Integer> future9 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000 + rand.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } return 100; }); CompletableFuture<Integer> future10 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000 + rand.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } return 200; }); // If one of the two is finished, then the Runnable is completableFuture <String> f = future10.applyToEither(future9, i-> i.toString()); // When both computations are completed, the Runnable is executed completableFuture f1 = future10. AcceptEx (future9,(e)->{System.out.println(e); }); System.out.println(f.get());
If you want to combine more than two completablefutures,allOf and anyOf will probably do the trick. The allOf method executes the calculation when all the completablefutures have been executed. The anyOf method is when any completableFuture finishes executing the computation, and the result is the same.

Having CompletableFuture makes it much easier to implement asynchronous programming ourselves, and this class also provides a number of ways to compose CompletableFuture. Combining Lambada expressions makes it easy to use.

Which thread executes the contents of f’s whenComplete depends on which thread X executes f.plete (). However, when the X thread executes f.plete () and whenComplete has not been executed (that is, the event has not been registered), the X thread will not synchronize the execution of the whenComplete callback. Whilst the thread that executes the event registration for whenComplete is responsible for synchronizing the event contents of the whenComplete.

The whencompleteAsync occasion is much simpler. In other words, take an empty thread from the thread pool or start a new thread to perform the callback. It has nothing to do with the thread that executes f.complete or the thread that executes whenCompleteAsync.