preface

In the past, when a task needed to be executed asynchronously, a Thread or Thread pool Executor was used to create it. If you need to return a value, you call Executor. Submit to get the Future. But what can we do when multiple threads have a dependency combination? Synchronization components such as CountDownLatch and CyclicBarrier can be used. An easy way to do this is to use CompeletableFuture

  • Creation of threaded tasks
  • Serial execution of a threaded task
  • Parallel execution of threaded tasks
  • Handle task results and exceptions
  • Simple combination of multitasking
  • The execution of the threaded task was cancelled
  • Obtaining task results and judging whether they are completed or not

Pay attention to the public number, communicate together, wechat search search: stealth forward

1 Create an asynchronous thread task

Create the CompletableFuture task from supplier

// Use the built-in thread ForkJoinPool.commonPool() to build tasks based on the supplier
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
// Specify a custom thread to build execution tasks from supplier
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
Copy the code

Create the CompletableFuture task from the Runnable

// Use the built-in thread ForkJoinPool.commonPool() to execute tasks based on runnable builds
public static CompletableFuture<Void> runAsync(Runnable runnable)
// Specify a custom thread that executes tasks based on a Runnable build
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
Copy the code
  • Use the sample
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> rFuture = CompletableFuture
        .runAsync(() -> System.out.println("hello siting"), executor);
/ / supplyAsync use
CompletableFuture<String> future = CompletableFuture
        .supplyAsync(() -> {
            System.out.print("hello ");
            return "siting";
        }, executor);

// Block and wait. RunAsync's Future returns null
System.out.println(rFuture.join());
// Block wait
String name = future.join();
System.out.println(name);
executor.shutdown(); // The thread pool needs to be closed-------- Output -------- hello sitingnull
hello siting
Copy the code

The constant value is returned as CompletableFuture

// Sometimes it is necessary to build a constant CompletableFuture
public static <U> CompletableFuture<U> completedFuture(U value)
Copy the code

The two threads are executed in serial

When the task is complete, the action is run, regardless of the result of a task, with no return value

public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
// Action is executed with the specified thread pool
public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor)
Copy the code
  • Use the sample
CompletableFuture<Void> future = CompletableFuture
        .supplyAsync(() -> "hello siting", executor)
        .thenRunAsync(() -> System.out.println("OK"), executor); executor.shutdown(); -------- Output -------- OKCopy the code

When the task is complete, the action is run, relying on the result of the previous task and returning no value

public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
// Action is executed with the specified thread pool
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)
Copy the code
  • Use the sample
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
        .supplyAsync(() -> "hello siting", executor) .thenAcceptAsync(System.out::println, executor); executor.shutdown(); -------- Output -------- hello sitingCopy the code

Task completion runs FN, which depends on the result of the previous task and has a return value

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)    
//fn executes with the specified thread pool
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
Copy the code
  • Use the sample
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
        .supplyAsync(() -> "hello world", executor)
        .thenApplyAsync(data -> {
            System.out.println(data); return "OK"; }, executor); System.out.println(future.join()); executor.shutdown(); -------- -------- Hello world OKCopy the code

ThenCompose – When the task is complete, run fn, which depends on the result of the previous task and has a return value

  • Similar to thenApply (except that thenCompose returns CompletionStage and thenApply returns U), this method is provided for better combination with other CompletableFuture tasks
public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) 
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn)
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,
		Executor executor)        
Copy the code
  • Use the sample
// The first asynchronous task, constant task
CompletableFuture<String> f = CompletableFuture.completedFuture("OK");
// The second asynchronous task
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
        .supplyAsync(() -> "hello world", executor)
        .thenComposeAsync(data -> {
            System.out.println(data); return f; // Use the first task as the return}, executor); System.out.println(future.join()); executor.shutdown(); -------- -------- Hello world OKCopy the code

3 Threads execute in parallel

The two CompletableFutures are executed in parallel, and then the action is executed, independent of the results of the previous two tasks, with no return value

public CompletableFuture<Void> runAfterBoth(CompletionStage
        other, Runnable action)
public CompletableFuture<Void> runAfterBothAsync(CompletionStage
        other, Runnable action)
public CompletableFuture<Void> runAfterBothAsync(CompletionStage
        other, Runnable action, Executor executor)
Copy the code
  • Use the sample
// The first asynchronous task, constant task
CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
        // The second asynchronous task
        .supplyAsync(() -> "hello siting", executor)
        // () -> system.out.println ("OK") is the third task
        .runAfterBothAsync(first, () -> System.out.println("OK"), executor); executor.shutdown(); -------- Output -------- OKCopy the code

The two CompletableFutures are executed in parallel, and then the action is executed, depending on the results of the two tasks, with no return value

// When the other task is completed in parallel, the action is executed. The action relies on consuming the results of the two tasks and returns no value
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)
// The two tasks are completed asynchronously, and fn relies on consuming the results of the two tasks. There is no return value and the default thread pool is used
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)  
// The two tasks complete asynchronously, fn (executed with the specified thread pool) then relies on consuming the results of the two tasks, and returns no value
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action, Executor executor) 
Copy the code
  • Use the sample
// The first asynchronous task, constant task
CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
        // The second asynchronous task
        .supplyAsync(() -> "hello siting", executor)
        // (w, s) -> system.out.println (s).thenAcceptBothAsync(first, (s, w) -> System.out.println(s), executor); executor.shutdown(); -------- Output -------- hello sitingCopy the code

The two CompleTableFutures execute in parallel, and then fn executes, depending on the results of the two tasks, with a return value

// After the other task is completed in parallel, fn is executed. Fn then relies on consuming the results of the two tasks and returns a value
public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, 
		BiFunction<? super T,? super U,? extends V> fn)
// The two tasks are completed asynchronously, and fn relies on consuming the results of the two tasks. It has a return value and uses the default thread pool
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn)   
// The two tasks are completed asynchronously, and fn (executed with the specified thread pool) relies on consuming the results of the two tasks, with a return value
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn, Executor executor)         
Copy the code
  • Use the sample
// The first asynchronous task, constant task
CompletableFuture<String> first = CompletableFuture.completedFuture("hello world");
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
        // The second asynchronous task
        .supplyAsync(() -> "hello siting", executor)
        // (w, s) -> system.out.println (s)
        .thenCombineAsync(first, (s, w) -> {
            System.out.println(s);
            return "OK"; }, executor); System.out.println(future.join()); executor.shutdown(); -------- Output -------- hello siting OKCopy the code

4 threads execute in parallel, whoever finishes first triggers the next task (whichever is the fastest)

If the previous task or the other task is complete, the action is run. The action does not depend on the result of the previous task and has no return value

public CompletableFuture<Void> runAfterEither(CompletionStage
        other, Runnable action)   
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage
        other, Runnable action)
// Action is executed with the specified thread pool
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage
        other, Runnable action, Executor executor)
Copy the code
  • Use the sample
// The first asynchronous task is hibernated for 1 second to ensure the latest execution
CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{
    try{ Thread.sleep(1000); }catch (Exception e){}
    System.out.println("hello world");
    return "hello world";
});
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
        // The second asynchronous task
        .supplyAsync(() ->{
            System.out.println("hello siting");
            return "hello siting";
        } , executor)
        //() -> system.out.println ("OK") is the third task
        .runAfterEitherAsync(first, () ->  System.out.println("OK") , executor); executor.shutdown(); -------- Output -------- hello siting OKCopy the code

If the previous task or other task is completed, the action is executed. The action depends on the result of the first completed task and has no return value

public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other,
		Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,
		Consumer<? super T> action, Executor executor)       
// Action is executed with the specified thread pool
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,
		Consumer<? super T> action, Executor executor)     
Copy the code
  • Use the sample
// The first asynchronous task is hibernated for 1 second to ensure the latest execution
CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{
    try{ Thread.sleep(1000);  }catch (Exception e){}
    return "hello world";
});
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture
        // The second asynchronous task
        .supplyAsync(() -> "hello siting", executor)
        // data -> system.out.println (data) is the third task.acceptEitherAsync(first, data -> System.out.println(data) , executor); executor.shutdown(); -------- Output -------- hello sitingCopy the code

If the previous task or other task completes, run fn, which returns a value depending on the result of the first completed task

public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other,
		Function<? super T, U> fn) 
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,
		Function<? super T, U> fn)         
//fn executes with the specified thread pool
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,
		Function<? super T, U> fn, Executor executor)         
Copy the code
  • Use the sample
// The first asynchronous task is hibernated for 1 second to ensure the latest execution
CompletableFuture<String> first = CompletableFuture.supplyAsync(()->{
    try{ Thread.sleep(1000);  }catch (Exception e){}
    return "hello world";
});
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture
        // The second asynchronous task
        .supplyAsync(() -> "hello siting", executor)
        // data -> system.out.println (data) is the third task
        .applyToEitherAsync(first, data ->  {
            System.out.println(data);
            return "OK"; } , executor); System.out.println(future); executor.shutdown(); -------- Output -------- hello siting OKCopy the code

5 Handle the task result or exception

Exceptionally – Handles exceptions

public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
Copy the code
  • If there was an exception in the previous handler, the call is exceptionally… catch
  • Use the sample
CompletableFuture<Integer> first = CompletableFuture
        .supplyAsync(() -> {
            if (true) {
                throw new RuntimeException("main error!");
            }
            return "hello world";
        })
        .thenApply(data -> 1)
        .exceptionally(e -> {
            e.printStackTrace(); // Exception capture processing, the first two processes can be caught daily
            return 0;
        });
Copy the code

Handle – Run fn when the task is complete or an exception occurs. The return value is fn

  • This is exceptionally capable of handling exceptions from the previous link as well as normal return values
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) 
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) 
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, 
		Executor executor)        
Copy the code
  • Use the sample
CompletableFuture<Integer> first = CompletableFuture
        .supplyAsync(() -> {
            if (true) { throw new RuntimeException("main error!"); }
            return "hello world";
        })
        .thenApply(data -> 1)
        .handleAsync((data,e) -> {
            e.printStackTrace(); // Exception capture handling
            returndata; }); System.out.println(first.join()); Output -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- java.util.concurrent.Com pletionException: Java. Lang. RuntimeException: the main error! .5 more
null
Copy the code

WhenComplete – When the task completes or an exception occurs, the action is run with a return value

  • WhenComplete is different from handle in that it does not participate in the processing of the returned result. It can be treated as a listener
  • Even if the exception is handled, the exception will reappear on the outer layer of the CompletableFuture
  • When whenCompleteAsync is used, the return result needs to be considered multi-threaded, since there are two threads working on the same result simultaneously
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,
		Executor executor)        
Copy the code
  • Use the sample
CompletableFuture<AtomicBoolean> first = CompletableFuture
        .supplyAsync(() -> {
            if (true) {  throw new RuntimeException("main error!"); }
            return "hello world";
        })
        .thenApply(data -> new AtomicBoolean(false))
        .whenCompleteAsync((data,e) -> {
            // The exception will be caught and handled, but the exception will still reappear in the outer layerSystem.out.println(e.getMessage()); }); first.join(); Output -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - Java. Lang. RuntimeException: the main error! Exception in thread"main"java.util.concurrent.CompletionException: java.lang.RuntimeException: main error! .5 more
Copy the code

6 Simple combination of multiple tasks

public static CompletableFuture<Void> allOf(CompletableFuture
       ... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture
       ... cfs)
Copy the code

  • Use the sample
 CompletableFuture<Void> future = CompletableFuture
        .allOf(CompletableFuture.completedFuture("A"),
                CompletableFuture.completedFuture("B"));
// All tasks need to be performed
future.join();
CompletableFuture<Object> future2 = CompletableFuture
        .anyOf(CompletableFuture.completedFuture("C"),
                CompletableFuture.completedFuture("D"));
// One of the tasks is finished
future2.join();
Copy the code

8 Cancel the threaded task

// mayInterruptIfRunning has no impact; If the task is not completed, an exception is returned
public boolean cancel(boolean mayInterruptIfRunning) 
// Whether to cancel the task
public boolean isCancelled(a)
Copy the code
  • Use the sample
CompletableFuture<Integer> future = CompletableFuture
        .supplyAsync(() -> {
            try { Thread.sleep(1000);  } catch (Exception e) { }
            return "hello world";
        })
        .thenApply(data -> 1);

System.out.println("Before the mission is cancelled :" + future.isCancelled());
// If the task is not completed, an exception is returned. you need to use exceptionally, handle to handle the result
future.cancel(true);
System.out.println("After the mission is cancelled :" + future.isCancelled());
future = future.exceptionally(e -> {
    e.printStackTrace();
    return 0; }); System.out.println(future.join()); -------- Output -------- Before the task is cancelled:falseAfter the task is cancelled:true
java.util.concurrent.CancellationException
	at java.util.concurrent.CompletableFuture.cancel(CompletableFuture.java:2276)
	at Test.main(Test.java:25)
0
Copy the code

9 Obtaining the task and determining whether the task has been completed

// Whether the task is completed
public boolean isDone(a)
// Block until the return value is obtained
public T join(a)
// Block until the return value is obtained. The difference is that get needs to return the checked exception
public T get(a)
// Wait to block for a period of time and get the return value
public T get(long timeout, TimeUnit unit)
// If not, return the specified value
public T getNow(T valueIfAbsent)
// If the task is not completed, use value as the result of the task execution, and the task ends. Future.get is required
public boolean complete(T value)
// If it is not completed, it is an exception call, and the exception result is returned, and the task ends
public boolean completeExceptionally(Throwable ex)
// Check whether the task ended due to an exception
public boolean isCompletedExceptionally(a)
// Force the return value to value, regardless of whether the task was completed before; Similar to complete
public void obtrudeValue(T value)
// Force an exception to be thrown and returned, regardless of whether the task was completed before; Similar completeExceptionally
public void obtrudeException(Throwable ex) 
Copy the code
  • Use the sample
CompletableFuture<Integer> future = CompletableFuture
        .supplyAsync(() -> {
            try { Thread.sleep(1000);  } catch (Exception e) { }
            return "hello world";
        })
        .thenApply(data -> 1);

System.out.println("Before the job is done :" + future.isDone());
future.complete(10);
System.out.println("Mission accomplished :"+ future.join()); -------- Output -------- Before the task is complete:falseAfter the task is completed:10
Copy the code

Welcome to correct any errors in the text