In daily development, it is often encountered that the foreground calls the service, then triggers a time-consuming asynchronous service, and returns the original service without waiting for the processing result of the asynchronous task. Here is a knowledge of Java asynchronous call. The following article attempts to summarize the various ways of Java asynchronous invocation.
1, By creating a new thread
First of all, we must realize that the essence of * * asynchronous call is actually executed by starting a new thread** For example:
public static void main(String[] args) throws Exception{ System.out.println("Main thread =====> start =====> " + System.currentTimeMillis()); new Thread(() -> { System.out.println("Asynchronous thread =====> start =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("Asynchronous thread =====> end =====> " + System.currentTimeMillis()); }).start(); Thread.sleep(2000); System.out.println("Main thread =====> end =====> " + System.currentTimeMillis()); }
The data results are as follows. We know that system Currenttimemillis() time unit is ms.
Main thread =====> start =====> 1627893837146 Asynchronous thread =====> start =====> 1627893837200 Main thread =====> end =====> 1627893839205 Asynchronous thread =====> end =====> 1627893842212
We use thread hibernation to achieve the effect that the execution time of the main thread is about 2 seconds and that of the asynchronous thread is about 5 seconds. Through the penultimate bit (second bit) of the printed timestamp, we can see that the total execution time of the two threads is about 5 seconds, which is in line with the characteristics of asynchronous execution
The above is the lambda writing method of using Runable to realize multi-threaded creation. For lambda knowledge, please refer to Java Lambda expression ; As for multiple implementations of multithreading, Java multithreaded transaction management It is mentioned in the article, which can be viewed step by step
2, Through thread pool
Because the implementation of asynchronous tasks is essentially performed by new threads, asynchronous execution can also be realized through the implementation of thread pool. It is written in the same way that we use thread pool to start multithreading. However, since our purpose is not to execute multithreading, but to execute tasks asynchronously, we generally need another thread.
Therefore, different from the commonly used newFixedThreadPool for executing multithreaded tasks, we use newsinglethreadexecution to create a thread pool for a single thread when executing 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 thread =====> start =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("Asynchronous thread =====> end =====> " + System.currentTimeMillis()); }); executorService.shutdown(); // Recycle thread pool Thread.sleep(2000); System.out.println("Main thread =====> end =====> " + System.currentTimeMillis()); }
The results are as follows:
Main thread =====> start =====> 1627895467578 Asynchronous thread =====> start =====> 1627895467635 Main thread =====> end =====> 1627895469644 Asynchronous thread =====> end =====> 1627895472649
It can be seen that the result is basically consistent with the first result.
Warm tip: don't forget to recycle the thread pool
3, Annotation via @ Async
As we all know, a very important feature of SpringBoot project is annotation. If your project is SpringBoot, you have another choice - @ Async annotation.
It is 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() 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, resulting in asynchronous thread interruption }
@Async public void asyncThread(){ System.out.println("Asynchronous thread =====> start =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("Asynchronous thread =====> end =====> " + System.currentTimeMillis()); }
The results are as follows:
Main thread =====> start =====> 1627897539948 Asynchronous thread =====> start =====> 1627897539956 Main thread =====> end =====> 1627897541965 Asynchronous thread =====> end =====> 1627897544966
There are two points to note:
- Similar to the @ transitional annotation, the method of @ Async annotation and the calling method cannot be in the same class, otherwise it will not take effect
- The design of JUnit framework does not consider the multithreading scenario, so after the main thread exits, the child thread will also exit immediately, so you can add multithread sleep time to observe the execution of asynchronous threads
4, Through completable future
Completable Future is jdk1 8 is an extension of Future. Completabilefuture implements the CompletionStage interface and Future interface, and increases the capabilities 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 thread =====> start =====> " + System.currentTimeMillis()); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("Asynchronous thread =====> end =====> " + System.currentTimeMillis()); },executorService); executorService.shutdown(); // Recycle thread pool Thread.sleep(2000); System.out.println("Main thread =====> end =====> " + System.currentTimeMillis()); }
Similar results can also be achieved as follows:
Main thread =====> start =====> 1627898354914 Asynchronous thread =====> start =====> 1627898354977 Main thread =====> end =====> 1627898356980 Asynchronous thread =====> end =====> 1627898359979
Completable future has very powerful functions and can bring us a very smooth programming experience. An article will be written later to introduce completable future in detail
Classification: [Java basics]
Tag: [multithreading]