This is the 26th day of my participation in the August More Text Challenge

Multithreading has been the difficulty in Java development, but also in the interview of frequent, while there is still time, I intend to consolidate the JUC knowledge, I think the opportunity is everywhere, but is always left to prepare for the people, I hope we can come on!!

Go down, come up again, I think we’ll be different.

CompletableFuture

What is CompletableFuture?

In Java, CompletableFuture is used for asynchronous programming. Asynchronous usually means non-blocking, allowing our task to run in a separate thread from the main thread, and we can get information about the execution status, completion, and exception of the asynchronous task in the main thread through callbacks.

In this way, the main thread is not blocked because the child thread is executing on another thread, so there is no need to wait until the child thread completes. The main thread can perform other tasks in parallel. This parallelism provides great provider performance.

CompletableFuture implements the Future, CompletionStage interface.

  1. To achieve theFutureinterfaceCompletableFutureCan now be compatible with the thread pool framework;
  2. CompletionStage Interface is asynchronous programming interface abstraction, which defines a variety of asynchronous methods, implementedCompletionStageMultiple abstract methods andFutureAnd use it together to create the powerful CompletableFuture class.

Future and CompletableFuture

CompletableFuture is an extension of the Future API.

Future represents the result of asynchronous computation. Methods are provided to check that the calculation is complete, wait for the calculation to complete, and retrieve the result of the calculation. The result can only be retrieved after the calculation is complete using the GET method, blocking if necessary until it is ready. Cancel the execution by the cancel method. Additional methods are provided to determine whether a task completed normally or was cancelled. Once the calculation is complete, it cannot be cancelled.

The main disadvantages of the Future are as follows: (1) There is no support for manual completion of the CompletableFuture. (2) The result of the Future cannot perform further operations without blocking

  • Future It doesn’t tell you it’s done, it provides a blockingget()Methods inform you of the results. You can’t put a callback into a Future whenFuture The result of the Future is automatically called with this callback when the result is available.

(3) Can not support the chain call

  • forFutureWe want to move on to the next oneFuture To create a chained call, which is not possible in the Future.
  • A chain call is a call that takes the result of one execution and passes it on to the next to use it, to form a chain. The chain of responsibility pattern, such as Filter on the Web.

(4) Multiple Future merging is not supported

  • Take me for example.FutrueComputes 10 squared, another Futrue computes 100 squared, and I have no way to directly combine them.

(5) Exception handling is not supported

  • The Future API does not have any exception-handling API, so it is very likely that errors will not be located at runtime.

  • The Future API:

  • public interface Future<V> {
    
        boolean cancel(boolean mayInterruptIfRunning); // Try to cancel this task.
    
        boolean isCancelled(a);// If the task is canceled before it completes normally, true is returned
    
        boolean isDone(a); // If this task completes, true is returned. Completion may be due to normal termination, exception, or cancellation -- in all cases, this method will return true
    
        V get(a) throws InterruptedException, ExecutionException; // Get the result of the task calculation
    
        V get(long timeout, TimeUnit unit) 
            throws InterruptedException, ExecutionException, TimeoutException;// How long can you wait to get the result of the task calculation
    }
    Copy the code

Three, the application

Create the CompletableFuture object

CompletableFuture provides four static methods to create a CompletableFuture object:

// The second argument to runAsync returns void indicates that we have created our own thread pool, otherwise the default is ForkJoinPool.commonPool().
public static CompletableFuture<Void>   runAsync(Runnable runnable)
public static CompletableFuture<Void>   runAsync(Runnable runnable, Executor executor)
SupplyAsync supplyAsync returns a result function. The second argument indicates that the thread pool is created by ourselves. Otherwise, the default is ForkJoinPool.commonPool().
//Supplier is a functional interface that stands for producer
public static <U> CompletableFuture<U>  supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U>  supplyAsync(Supplier<U> supplier, Executor executor)
Copy the code

3.2 Scenario 1: Take the initiative to complete the task

Scenario: Create a CompletableFuture in the main thread, then the main thread calls the get method and blocks, and finally we terminate it in a child thread.

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo1 {

    /** * Create a CompletableFuture in the main thread, then the main thread calls the get method and blocks, and finally we terminate it in a child thread **@param args
     */
    public static void main(String[] args) throws Exception {
        CompletableFuture<String> future = new CompletableFuture<>();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "The child thread is working.");
                // Child thread sleeps for 5 seconds
                Thread.sleep(5000);
// // completes the main thread in the child thread and if you comment out this line of code will stop forever
                future.complete("success");
            } catch(Exception e) { e.printStackTrace(); }},"A").start();
        // The main thread calls the get method blocked
        System.out.println(The main thread calls the get method and gets: + future.get());
        System.out.println("Main thread complete, blocking end!!!!!!"); }}Copy the code

Scenario 2: Asynchronous task with no return value

RunAsync: Returns a new CompletableFuture completed asynchronously by the task running at ForkJoinPool.commonPool() after the given operation is run.

You can use runAsync if you want to run a background task asynchronously without the task returning results

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo2 {

    /** * Asynchronous task ** with no return value@param args
     */
    public static void main(String[] args) throws Exception {
        System.out.println("Main thread started");
        // Run an asynchronous task with no return value
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                System.out.println("Child thread starts work");
                Thread.sleep(5000);
                System.out.println("Child thread complete");
            } catch(Exception e) { e.printStackTrace(); }});// Main thread is blocked
        future.get();
        System.out.println("End of main thread"); }}Copy the code

3.4 Scenario 3: Asynchronous Task with return value

SupplyAsync: Returns the result of the task.

CompletableFuture. SupplyAsync () it holds: supplier and return CompletableFuture < T > < T >, T is by calling the incoming: supplier to achieve the value of the type.

Supplier

is a simple functional interface that represents the result of Supplier. It has a get() method that writes to your background tasks and returns results.

public static <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier) {
    return asyncSupplyStage(ASYNC_POOL, supplier);
}
Copy the code
/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo2 {

    /** * Asynchronous task ** that has a return value@param args
     */
    public static void main(String[] args) throws Exception {
        System.out.println("Main thread started");
        // Run an asynchronous task with no return value
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("Child thread starts work");
                Thread.sleep(5000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "Child thread task completed";
        });
        // Main thread is blocked
        System.out.println(future.get());
        System.out.println("End of main thread"); }}/** * main thread starts * child thread starts work * child thread completes * Main thread ends */

Copy the code

3.5 scenario 4: Thread serialization

When one thread depends on another, the thenApply method can be used to serialize the two threads.

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo4 {

    private static String action="";

    /** * thread dependent * 1, I went to the barbecue shop, * 2, began to point barbecue * 3, and friends after the barbecue, to bring milk tea back to my girlfriend *@param args
     */
    public static void main(String[] args) throws Exception {
        System.out.println("Main thread started");
        CompletableFuture<String> future =
                CompletableFuture.supplyAsync(() -> {
                    action="Go to a barbecue with a friend!!!! ";
                    return action;
                }).thenApply(string -> {
                    return  action+="Go to the store -- > start ordering barbecue!!";
                }).thenApply(String->{
                    return  action+="Bring your girlfriend a cup of milk tea after a barbecue with your friends!!";
                });
        String str = future.get();
        System.out.println("The main thread ends and the child thread results in :"+ str); }}/** The main thread starts the main thread ends, and the result of the child thread is: go to a barbecue with friends!! Go to the store -- > start ordering barbecue!! After a barbecue with friends, bring your girlfriend a cup of milk tea!! * /
Copy the code

3.6 Scenario 5: thenAccept Consumption processing result

If you don’t want to return anything from your callback function and just want to run some snippet after the Future completes, you can use thenAccept() and thenRun() methods, which are often used in the last callback function at the end of the call chain.

ThenAccept consumes the processing result, receives the processing result of the task, and consumes the processing, with no result returned.

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo5 {

    private static String action = "";

    public static void main(String[] args) throws Exception {
        System.out.println("Main thread started");
        CompletableFuture.supplyAsync(() -> {
            try {
                action = "Shopping on Taobao, looking for a pair of shoes.";
            } catch (Exception e) {
                e.printStackTrace();
            }
            return action;
        }).thenApply(string -> {
            return action + "Selected, order successful!!";
        }).thenApply(String -> {
            return action + "Waiting for the delivery";
        }).thenAccept(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("The child thread completes all processing and finally calls ACCEPT, resulting in :"+ s); }}); }}/** The main thread completes the processing, and finally calls accept, resulting in: shopping taobao, want to buy a pair of shoes waiting for the delivery */
Copy the code

3.7 Scenario 6: Exception Handling

Exceptions are exceptionally handled, which is triggered when an exception occurs, and the callback gives you a chance to recover from errors generated in the original Future. You can log the exception here and return a default value.

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo6 {


    public static void main(String[] args) throws Exception{
        System.out.println("Main thread started");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i= 1/0;
            System.out.println("Child thread executing");
            return i;
        }).exceptionally(ex -> {
            System.out.println(ex.getMessage());
            return -1; }); System.out.println(future.get()); }}/ * * * the main thread to start * Java. Lang. ArithmeticException: / by zero * 1 * /
Copy the code

Using the handle() method to handle exceptions API provides a more general method – handle() to recover from exceptions, which is called whether an exception has occurred or not

CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("Mission initiated.");
    int i=0/1;
    return i;
}).handle((i,ex) -> {
    System.out.println("Enter handle method");
    if(ex ! =null) {
        System.out.println("An exception has occurred. The content is :" + ex.getMessage());
        return -1;
    } else {
        System.out.println("Normally completed, content:" + i);
        returni; }});Copy the code

3.8 scenario 7: Result Merge

ThenCompose merges the execution results of two dependent CompletableFutures

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo7 {

    private static Integer num = 10;

    public static void main(String[] args) throws Exception {
        System.out.println("Main thread started");
        // Add 10 to the first step
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("Let the num + 10; Mission begins.");
            num += 10;
            return num;
        });
        / / merge
        CompletableFuture<Integer> future1 = future.thenCompose(i ->
                // One more CompletableFuture
                CompletableFuture.supplyAsync(() -> {
                    return i + 1; })); System.out.println(future.get()); System.out.println(future1.get()); }}/** * let num+10; Task starts * 20 * 21 */
Copy the code

ThenCombine combines two CompletableFutures tasks that have no dependencies

package com.crush.juc09;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo8 {

    private static Integer sum = 0;
    private static Integer count = 1;


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

        System.out.println("Main thread started");

        CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("From a 1 +... + 50 start");
            for (int i=1; i<=50; i++){ sum+=i; } System.out.println("sum::"+sum);
            return sum;
        });

        CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("From a 1 *... * 10 start");

            for (int i=1; i<=10; i++){ count=count*i; } System.out.println("count::"+count);

            return count;
        });

        // Merge the two results
        CompletableFuture<Object> future = job1.thenCombine(job2, new
                BiFunction<Integer, Integer, List<Integer>>() {
                    @Override
                    public List<Integer> apply(Integer a, Integer b) {
                        List<Integer> list = new ArrayList<>();
                        list.add(a);
                        list.add(b);
                        returnlist; }}); System.out.println("The combined result is :"+ future.get()); }}/** The main thread starts from 1*... *10 starts from 1+... +50 Start sum::1275 count::3628800 The combined result is [1275, 3628800] */
Copy the code

3.9 Scenario 8: Merging the results of multiple tasks

AllOf the anyOf

AllOf: A series of separate future tasks that do something after all their tasks have been completed

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo9 {

    private static Integer num = 10;


    public static void main(String[] args) throws Exception{
        System.out.println("Main thread started");
        List<CompletableFuture> list = new ArrayList<>();

        CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("The plus 10 mission begins.");
            num += 10;
            return num;
        });
        list.add(job1);

        CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Multiply by 10 and the mission begins.");
            num = num * 10;
            return num;
        });
        list.add(job2);

        CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Minus 10 missions to begin with.");
            num = num - 10;
            return num;
        });
        list.add(job3);

        CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
            System.out.println("Divide by 10 and the task begins.");
            num = num / 10;
            return num;
        });
        list.add(job4);

        // Multitask mergeList<Integer> collect = list.stream().map(CompletableFuture<Integer>::join).collect(Collectors.toList()); System.out.println(collect); }}/** Main thread start times 10 task start plus 10 task start minus 10 task start divided by 10 task start [110, 100, 100, 10] */
Copy the code

AnyOf: The entire task can be completed if only one of multiple futures is returned, rather than waiting for each future to be completed

package com.crush.juc09;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/ * * *@Author: crush
 * @Date: 2021-08-23 9:08
 * version 1.0
 */
public class CompletableFutureDemo10 {

    private static Integer num = 10;
    /** ** add 10 to a number, then square *@param args
     */
    public static void main(String[] args) throws Exception{
        System.out.println("Main thread started");

        CompletableFuture<Integer>[] futures = new CompletableFuture[4];
        CompletableFuture<Integer> job1 = CompletableFuture.supplyAsync(() -> {
            try{
                Thread.sleep(5000);
                System.out.println("The plus 10 mission begins.");
                num += 10;
                return num;
            }catch (Exception e){
                return 0; }}); futures[0] = job1;
        CompletableFuture<Integer> job2 = CompletableFuture.supplyAsync(() -> {
            try{
                Thread.sleep(2000);
                System.out.println("Multiply by 10 and the mission begins.");
                num = num * 10;
                return num;
            }catch (Exception e){
                return 1; }}); futures[1] = job2;
        CompletableFuture<Integer> job3 = CompletableFuture.supplyAsync(() -> {
            try{
                Thread.sleep(3000);
                System.out.println("Minus 10 missions to begin with.");
                num = num - 10;
                return num;
            }catch (Exception e){
                return 2; }}); futures[2] = job3;
        CompletableFuture<Integer> job4 = CompletableFuture.supplyAsync(() -> {
            try{
                Thread.sleep(4000);
                System.out.println("Divide by 10 and the task begins.");
                num = num / 10;
                return num;
            }catch (Exception e){
                return 3; }}); futures[3] = job4; CompletableFuture<Object> future = CompletableFuture.anyOf(futures); System.out.println(future.get()); }}// The main thread starts
// Multiply by 10 to start the task
/ / 100
Copy the code

Four, summary

This article is only a brief introduction, but we still need a deeper understanding.

🌈 talk to yourself

Recently, I started to learn JUC again. I feel there is a lot of Java content, but I still think I need to lay a solid foundation in order to go further.

Recently in the continuous update, if you feel helpful to you, also interested in words, follow me, let us

Let’s study and discuss.

Hello, I am ning Zhichun, a blogger, a small seed on the way of Learning Java. I also hope that one day I can take root and grow into a tree in the sky.

Hope to share with you 😁

We: when we meet, we have achieved something.