In daily development, it is often encountered that the foreground calls the service, and then triggers a time-consuming asynchronous service, and does not need to wait for the processing result of the asynchronous task to return to the original service. Here is a knowledge of Java asynchronous calls involved. The following article attempts to generalize the various ways Java asynchronous calls can be made.

By creating a new thread


The first thing we need to realize is that asynchronous calls are actually executed by starting a new thread. ** Here is an example:

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

    System.out.println("Main thread =====> Start =====>" + System.currentTimeMillis());

    new Thread(() -> {
        System.out.println("Asynchronous threads =====> Start =====>" + System.currentTimeMillis());
        try{
            Thread.sleep(5000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("Asynchronous threads =====> End =====>" + System.currentTimeMillis());
    }).start();

    Thread.sleep(2000);

    System.out.println("Main thread =====> End =====>" + System.currentTimeMillis());

}

Copy the code

As shown below, we know that system.currentTimemillis () time unit is ms.

Main thread =====> Start =====>1627893837146Asynchronous threads =====> Start =====>1627893837200Main thread =====> End =====>1627893839205Asynchronous threads =====> End =====>1627893842212

Copy the code

We use thread sleep to achieve the main thread execution time of about 2 seconds, asynchronous thread execution of about 5 seconds effect. According to the fourth bit from the last of the printed timestamp (second bit), we can see that the total execution time of the two threads is about 5 seconds, which conforms to the characteristics of asynchronous execution

The above is the use of Runable to achieve multithreaded creation of the way to write lambda, about the lambda knowledge, can refer to Java lambda expressions; And about multithreaded implementation, Java multithreaded transaction management article has been mentioned, can be moved to view

2. Through thread pools


Because asynchronous tasks are implemented by the nature of the new thread executing the task, it is possible to execute asynchronously through a thread pool. Write in the same way that we used thread pools to start multithreading. But since our goal is not to execute multiple threads, but to execute tasks asynchronously, we usually need another thread.

So instead of using newFixedThreadPool for multi-threaded tasks, we use newSingleThreadExecutor to create a pool of single threads for asynchronous tasks.

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

    System.out.println("Main thread =====> Start =====>" + System.currentTimeMillis());

    ExecutorService executorService = Executors.newSingleThreadExecutor();
    executorService.submit(()->{
        System.out.println("Asynchronous threads =====> Start =====>" + System.currentTimeMillis());
        try{
            Thread.sleep(5000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("Asynchronous threads =====> End =====>" + System.currentTimeMillis());
    });
    executorService.shutdown(); // Reclaim the thread pool

    Thread.sleep(2000);

    System.out.println("Main thread =====> End =====>" + System.currentTimeMillis());

}

Copy the code

The execution result is as follows:

Main thread =====> Start =====>1627895467578Asynchronous threads =====> Start =====>1627895467635Main thread =====> End =====>1627895469644Asynchronous threads =====> End =====>1627895472649

Copy the code

As you can see, the results are pretty much the same as the first one.

Tips: Don’t forget to recycle the thread pool

Third, through @async annotation


As we all know, one of the most important features of the SpringBoot project is annotation. If your project is SpringBoot, there is another option – @async annotation.

It’s also very simple to use, encapsulate the code to be executed asynchronously into a method, annotate the method with @async, and then call it directly in the main method.

@Test
public void mainThread(a) throws Exception{

    System.out.println("Main thread =====> Start =====>" + System.currentTimeMillis());
    collectionBill.asyncThread();
    Thread.sleep(2000);
    System.out.println("Main thread =====> End =====>" + System.currentTimeMillis());

    Thread.sleep(4000); // Used to prevent the JVM from stopping, causing asynchronous thread interrupts
}

Copy the code
@Async
public void asyncThread(a){
    System.out.println("Asynchronous threads =====> Start =====>" + System.currentTimeMillis());
    try{
        Thread.sleep(5000);
    }catch (InterruptedException e){
        e.printStackTrace();
    }
    System.out.println("Asynchronous threads =====> End =====>" + System.currentTimeMillis());
}

Copy the code

The execution result is as follows:

Main thread =====> Start =====>1627897539948Asynchronous threads =====> Start =====>1627897539956Main thread =====> End =====>1627897541965Asynchronous threads =====> End =====>1627897544966

Copy the code

There are two points to note:

  1. similar@TranctionalAnnotations,@AsyncThe annotated method cannot be in the same class as the calling method, otherwise it will not take effect
  2. The JUnit framework is not designed for multi-threaded scenarios, so when the main thread exits, the child thread exits immediately, so you can add a multi-threaded sleep time to watch the asynchronous thread execute

4. Through CompletableFuture


CompletableFuture is a new feature in JDK1.8 and is an extension to a Future. CompletableFuture implements the CompletionStage interface and the Future interface, and adds the ability of asynchronous callback, streaming processing, and multiple Future combination processing.

The implementation code is as follows:

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

    System.out.println("Main thread =====> Start =====>" + System.currentTimeMillis());

    ExecutorService executorService = Executors.newSingleThreadExecutor();
    CompletableFuture.runAsync(() ->{
        System.out.println("Asynchronous threads =====> Start =====>" + System.currentTimeMillis());
        try{
            Thread.sleep(5000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("Asynchronous threads =====> End =====>" + System.currentTimeMillis());
    },executorService);
    executorService.shutdown(); // Reclaim the thread pool

    Thread.sleep(2000);

    System.out.println("Main thread =====> End =====>" + System.currentTimeMillis());

}

Copy the code

Similar results can be achieved as follows:

Main thread =====> Start =====>1627898354914Asynchronous threads =====> Start =====>1627898354977Main thread =====> End =====>1627898356980Asynchronous threads =====> End =====>1627898359979

Copy the code

CompletableFuture has very powerful functions, which can bring us a very smooth programming experience. I’ll write an article about CompletableFuture in more detail

[Java Basics]

[Multithread]