CompletableFuture

Four static methods

  • RunAsync (no return value)

    1. public static CompletableFuture runAsync(Runnable runnable)

    2. public static CompletableFuture runAsync(Runnable runnable, Executor executor)

  • SupplyAsync (return value)

    1. public static CompletableFuture supplyAsync(Supplier supplier)

    2. public static CompletableFuture supplyAsync(Supplier supplier, Executor executor)

The Executor Executor parameter, when not specified, defaults to ForkJoinPool.commonPool() as a thread pool to execute asynchronous code

Code examples:
ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 8, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); CompletableFuture. RunAsync (() - > {System. Out. Println (" don't specify a Thread pool parameter, the current Thread: "+ Thread. The currentThread (). The getName ()); }); CompletableFuture. RunAsync (() - > {System. Out. Println (" specified parameters of the Thread pool, the current Thread: "+ Thread. The currentThread (). The getName ()); }, executor); executor.shutdown();Copy the code
Output result:
If pool-1-thread-1 is specified, the current thread is ForkJoinPool.com monpool-worker-3Copy the code

Commonly used method

1. Get results and trigger calculations

Get results:

  • Public T get() // block until the calculation is complete
  • Public T join() // block until the calculation is complete
  • Public T get(long timeout, TimeUnit Unit) // Wait for the specified time. If no result is obtained after the specified time, an exception is thrown
  • Public T getNow(T valueIfAbsent) // Obtains the result immediately, calculates the return result, and does not calculate the return value valueIfAbsent

Code examples:

Integer result = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return 123;
}).join();
System.out.println(result);

CompletableFuture<Integer> futureResult = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return 123;
});
System.out.println(futureResult.get());
System.out.println(futureResult.getNow(456));
System.out.println(futureResult.get(2, TimeUnit.SECONDS));
Copy the code

Active trigger calculation:

  • public boolean complete(T value)

Code examples:

public static void main(String[] args) throws InterruptedException, ExecutionException { CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return 11; }); // When get() is blocked, the complete method ends the block and get() gets the value of the set complete system.out.println (future.complete(666)); // Print true system.out.println (future.get()); // output 666}Copy the code

2. Process the calculation results

  • thenApply
  • handle

When one thread depends on another, handle is used to serialize the two threads

public static void main(String[] args) throws InterruptedException {

    CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(11);
        return 11;
    }).handle((r, e) -> {
        System.out.println(22);
        return r + 1;
    }).handle((r, e) -> {
        System.out.println(33);
        return r + 1;
    }).exceptionally(e -> {
        e.printStackTrace();
        return null;
    });

    TimeUnit.SECONDS.sleep(2);
}
Copy the code

3. Consume the calculated results

  • thenRun

After task A is finished, execute task B, which does not need the result of A

CompletableFuture.runAsync(() -> {
    System.out.println(Thread.currentThread().getName());
}).thenRun(() -> System.out.println("finish"));
Copy the code
  • thenAccept

Task B needs the result of task A, but task B has no return value

CompletableFuture.supplyAsync(() -> {
    System.out.println(Thread.currentThread().getName());
    return 1;
}).thenAccept(System.out::println);
Copy the code
  • thenApply

After task A is finished, execute task B, which needs the result of A and has A value returned by task B

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    System.out.println(Thread.currentThread().getName());
    return 1;
}).thenApply(a -> {
    // 1
    System.out.println(a);
    return a + 1;
}).thenApply(b -> {
    // 2
    System.out.println(b);
    return b + 2;
});
// 4
System.out.println(future.get());
Copy the code

4. Choose the speed of calculation (who uses quickly)

  • applyToEither

Sample code:

CompletableFuture < Integer > future = CompletableFuture. SupplyAsync (() - > {System. Out. Println (" thread 1: "+ thread.currentThread ().getName() "); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }). ApplyToEither (CompletableFuture supplyAsync (() - > {System. Out. Println (" thread 2: "+ thread.currentThread ().getName() "); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 20; }), f -> {system.out.println (" who calculates fast who "); return f + 1; }); System.out.println(future.get());Copy the code

Output result:

Thread 1:ForkJoinPool.com starting monPool - worker - 3 thread 2:ForkJoinPool.com starting monPool - worker - 5 Whoever computing fast with 11Copy the code

5. Combine the calculated results

  • thenCombine

Usage scenario: Requests data from multiple interfaces and returns the data after merging

Sample code:

CompletableFuture < Integer > future = CompletableFuture. SupplyAsync (() - > {System. Out. Println (" thread 1: " + Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }). ThenCombine (CompletableFuture supplyAsync (() - > {System. Out. Println (" Thread 2: "+ Thread. CurrentThread (). The getName ()); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 20; }), (a, b) -> {system.out.println (); return a + b; }); System.out.println(future.get());Copy the code

Output result:

Thread 1 forkJoinpool.com monpool-worker-3 Thread 2 Forkjoinpool.com monpool-worker-7 Merges the results 30Copy the code

The sample

Multi-platform commodity price comparison, two ways of execution time comparison

import java.util.List; import java.util.concurrent.*; import java.util.stream.Collectors; public class CompletableFutureNetMallDemo { static List<NetMall> list = List.of(new NetMall("jd"), new NetMall("pdd"), new NetMall("tmall"), new NetMall("taobao"), new NetMall("dangdang"), new NetMall("shop1"), new NetMall("shop2"), new NetMall("shop3"), new NetMall("shop4"), new NetMall("shop5")); public static void main(String[] args) { var start = System.currentTimeMillis(); var firstList = getPriceByStep(list, "Java"); for (String s : firstList) { System.out.println(s); + (system.currentTimemillis () -start) + "milliseconds "); var start1 = System.currentTimeMillis(); var secondList = getPriceAsync(list, "Java"); for (String s : secondList) { System.out.println(s); } system.out.println ("CompletableFuture asynchronous operation execution time: "+ (system.currentTimemillis () -start1) +" milliseconds "); } public static list <String> public static list <String> getPriceByStep(List<NetMall> list, String productName) { return list.stream() .map(netMall -> String.format(productName + " in %s price is %.2f", netMall.getMallName(), netMall.calcPrice(productName))) .collect(Collectors.toList()); } /** * CompletableFuture asynchronous operation ** @param list platform list * @param productName productName * @return calculation result */ public static List<String> getPriceAsync(List<NetMall> list, String productName) { return list.stream() .map(netMall -> CompletableFuture.supplyAsync(() -> String.format(productName  + " in %s price is %.2f", netMall.getMallName(), netMall.calcPrice(productName)))) .collect(Collectors.toList()) .stream().map(CompletableFuture::join) .collect(Collectors.toList()); } } class NetMall { private final String mallName; public String getMallName() { return mallName; } public NetMall(String mallName) { this.mallName = mallName; } public double calcPrice(String productName) {// Return a random number return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0); }}Copy the code