In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces "Future pattern introduction and SpringBoot asynchronous programming example analysis". In daily operation, I believe many people have doubts about the introduction of Future mode and the analysis of SpringBoot asynchronous programming examples. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "Future mode introduction and SpringBoot asynchronous programming example analysis". Next, please follow the editor to study!
Through this article, you can learn the following knowledge points:
Introduction of Future model and its core idea
The difference between the number of core threads and the maximum number of threads, what does the queue capacity represent?
ThreadPoolTaskExecutor saturation strategy
SpringBoot asynchronous programming practice, understand the execution logic of the code.
Future mode
Asynchronous programming is very useful in dealing with time-consuming operations and multitasking scenarios, and we can make better use of the machine's CPU and memory and improve their utilization. There are many kinds of multithreaded design patterns. Future pattern is a very common design pattern in multithreaded development. This paper is also based on this pattern to explain SpringBoot's knowledge of asynchronous programming.
Before the actual combat, let me briefly introduce the core idea of the Future model.
The core idea of Future pattern is asynchronous invocation. When we execute a method, if there are multiple time-consuming tasks in the method that need to be done at the same time, and we are in no hurry to wait for the result, we can ask the client to return immediately, and then the background slowly calculates the task. Of course, you can also choose to wait until these tasks are finished, and then return to the client. This is well supported in Java, and I will compare the differences between the two approaches in detail in a later sample program.
Practice of SpringBoot Asynchronous programming
If we need to implement asynchronous programming in SpringBoot, the two annotations provided through Spring will make this very easy.
EnableAsync: enable support for asynchronous methods by adding @ EnableAsync to the configuration class or Main class.
@ Async can act on a class or on a method, and all methods acting on a class represent that class are asynchronous methods.
1. Custom TaskExecutor
Many people don't know much about TaskExecutor, so let's take a little space to introduce this thing first. From the name, we can see that it is the executor of the task, it leads the thread to process the task, just like the commander, and our thread is like an army, which can attack the enemy asynchronously.
Spring provides the TaskExecutor interface as an abstraction for task executors, much like the Executor interface under the java.util.concurrent package. A slightly different TaskExecutor interface uses the syntax of Java 8 @ FunctionalInterface to declare that the interface is a functional interface.
Org.springframework.core.task.TaskExecutor@FunctionalInterfacepublic interface TaskExecutor extends Executor {void execute (Runnable var1);}
If there is no custom Executor, Spring creates a SimpleAsyncTaskExecutor and uses it.
Import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.AsyncConfigurer;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;/** @ author shuang.kou * / @ Configuration@EnableAsyncpublic class AsyncConfig implements AsyncConfigurer {private static final int CORE_POOL_SIZE = 6; private static final int MAX_POOL_SIZE = 10; private static final int QUEUE_CAPACITY = 100 The default configuration of @ Bean public Executor taskExecutor () {/ / Spring is that the number of core threads is 1, the maximum thread capacity is unlimited, and the queue capacity is unlimited. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor (); / / number of core threads executor.setCorePoolSize (CORE_POOL_SIZE); / / maximum number of threads executor.setMaxPoolSize (MAX_POOL_SIZE); / / queue size executor.setQueueCapacity (QUEUE_CAPACITY); / / when the maximum pool is full, this policy ensures that task requests are not lost, but may affect the overall performance of the application. Executor.setRejectedExecutionHandler (new ThreadPoolExecutor.CallerRunsPolicy ()); executor.setThreadNamePrefix ("My ThreadPoolTaskExecutor-"); executor.initialize (); return executor;}}
Common ThreadPoolTaskExecutor concepts:
Core Pool Size: the number of core threads defines the minimum number of threads that can run simultaneously.
Queue Capacity: when a new task arrives, it will first determine whether the number of threads currently running reaches the number of core threads, and if so, the trust will be stored in the queue.
Maximum Pool Size: when the tasks stored in the queue reach the queue capacity, the current number of threads that can run simultaneously becomes the maximum number of threads.
In general, the queue size will not be set to: Integer.MAX_VALUE, nor will the number of core threads and the maximum number of threads be set to the same size, so the setting of the maximum number of threads is meaningless, and you are not sure about the current CPU and memory utilization.
What happens if a new task comes in when the queue is full and the number of threads currently running at the same time reaches the maximum number of threads?
Spring uses ThreadPoolExecutor.AbortPolicy by default. By default in Spring, ThreadPoolExecutor will throw a RejectedExecutionException to reject a new task, which means that you will lose the processing of the task. For scalable applications, ThreadPoolExecutor.CallerRunsPolicy is recommended. This policy provides us with scalable queues when the maximum pool is filled.
ThreadPoolTaskExecutor saturation policy definition:
If the current number of simultaneous threads reaches the maximum number of threads, ThreadPoolTaskExecutor defines some policies:
ThreadPoolExecutor.AbortPolicy: throws a RejectedExecutionException to reject the processing of a new task.
ThreadPoolExecutor.CallerRunsPolicy: call to execute your own thread to run the task. You will not make a task request. However, this strategy will slow down the submission speed of new tasks and affect the overall performance of the program. In addition, this strategy likes to increase queue capacity. You can choose this strategy if your application can withstand this delay and you cannot discard any task requests.
ThreadPoolExecutor.DiscardPolicy: don't deal with new tasks, just discard them.
ThreadPoolExecutor.DiscardOldestPolicy: this policy discards the earliest outstanding task requests.
two。 Write an asynchronous method
Let's simulate a method to find the movie at the beginning of the corresponding character, and we annotate this method with @ Async to tell Spring that it is an asynchronous method. In addition, the return value of this method CompletableFuture.completedFuture (results) means that we need to return the result, which means that the program must complete the task and then return it to the user.
Please note that the first line of the completableFutureTask method prints the log, which will be used later in the analysis program, which is very important!
Import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.concurrent.CompletableFuture;import java.util.stream.Collectors;/** @ author shuang.kou * / @ Servicepublic class AsyncService {private static final Logger logger = LoggerFactory.getLogger (AsyncService.class) Private List movies = new ArrayList (Arrays.asList ("Forrest Gump", "Titanic", "Spirited Away", "The Shawshank Redemption", "Zootopia", "Farewell", "Joker", "Crawl")) / * * demonstration use: find the movie at the beginning of a specific character / string * / @ Async public CompletableFuture completableFutureTask (String start) {/ / print log logger.warn (Thread.currentThread (). GetName () + "start this task!"); / / find the movie List results = movies.stream (). Filter (movie-> movie.startsWith (start)) .movie (Collectors.toList ()) / / simulate that this is a time-consuming task try {Thread.sleep (1000L);} catch (InterruptedException e) {e.printStackTrace ();} / / returns a new CompletableFuture that has been completed with the given value. Return CompletableFuture.completedFuture (results);}}
3. Asynchronous method of test writing
/ * * @ author shuang.kou * / @ RestController@RequestMapping ("/ async") public class AsyncController {@ Autowired AsyncService asyncService; @ GetMapping ("/ movies") public String completableFutureTask () throws ExecutionException, InterruptedException {/ / start time long start = System.currentTimeMillis (); / / start a large number of asynchronous tasks List words = Arrays.asList ("F", "T", "S", "Z", "J", "C") List completableFutureList = words.stream () .map (word-> asyncService.completableFutureTask (word)) .results (Collectors.toList ()); / / CompletableFuture.join () method can get their results and join the results together List results = completableFutureList.stream (). Map (CompletableFuture::join) .map (Collectors.toList ()) / / print the result and the time it takes to run the program System.out.println ("Elapsed time:" + (System.currentTimeMillis ()-start)); return results.toString ();}}
Request this interface, and the console prints out the following:
2019-10-01 13 g.j.a.service.AsyncService 50 g.j.a.service.AsyncService 17.007 WARN 18793-[lTaskExecutor-1]: My ThreadPoolTaskExecutor-1start this task!
2019-10-01 13 g.j.a.service.AsyncService 50 g.j.a.service.AsyncService 17.007 WARN 18793-[lTaskExecutor-6]: My ThreadPoolTaskExecutor-6start this task!
2019-10-01 13 g.j.a.service.AsyncService 50 g.j.a.service.AsyncService 17.007 WARN 18793-[lTaskExecutor-5]: My ThreadPoolTaskExecutor-5start this task!
2019-10-01 13 g.j.a.service.AsyncService 50 g.j.a.service.AsyncService 17.007 WARN 18793-[lTaskExecutor-4]: My ThreadPoolTaskExecutor-4start this task!
2019-10-01 13 g.j.a.service.AsyncService 50 g.j.a.service.AsyncService 17.007 WARN 18793-[lTaskExecutor-3]: My ThreadPoolTaskExecutor-3start this task!
2019-10-01 13 g.j.a.service.AsyncService 50 g.j.a.service.AsyncService 17.007 WARN 18793-[lTaskExecutor-2]: My ThreadPoolTaskExecutor-2start this task!
Elapsed time: 1010
First of all, we can see that the time taken to process all tasks is about 1 s. This is related to our custom ThreadPoolTaskExecutor, where the number of core threads we configured is 6, and then six tasks are assigned to the system for execution through the following code simulation. In this way, each thread is assigned a task, and each task takes 1 s to execute, so the total time spent processing 6 tasks is 1 s.
List words = Arrays.asList ("F", "T", "S", "Z", "J", "C"); List completableFutureList = words.stream () .map (word-> asyncService.completableFutureTask (word)) .duration (Collectors.toList ())
You can verify it yourself and try to change the number of core threads to 3. If you ask this interface again, you will find that it takes about 2 seconds to process all tasks.
In addition, as you can see from the above running results, the results are not returned until all tasks have been executed. This situation corresponds to the case where we need to return the result to the client request, what if we do not need to return the task execution result to the client? For example, if we upload a large file to the system, we will upload it successfully as long as the format of the large file meets the requirements. Normally we need to wait for the file to be uploaded before returning the message to the user, but this will be slow. In the case of asynchronism, when the user uploads, the message is returned to the user immediately, and then the system silently processes the upload task. This will also add a little bit of trouble, because the file may fail to upload, so the system also needs a mechanism to compensate for this problem, such as sending a message to notify the user when there is a problem with the upload.
The following demonstrates a situation where the client does not need to return a result:
Change the completableFutureTask method to the void type
@ Asyncpublic void completableFutureTask (String start) {. / / this may be the system's processing of the results of task execution, such as storing it in the database and so on. / / doSomeThingWithResults (results);}
The Controller code is modified as follows:
@ GetMapping ("/ movies") public String completableFutureTask () throws ExecutionException, InterruptedException {/ / Start the clock long start = System.currentTimeMillis (); / / Kick of multiple, asynchronous lookups List words = Arrays.asList ("F", "T", "S", "Z", "J", "C"); words.stream () .forEach (word-> asyncService.completableFutureTask (word)) / / Wait until they are all done / / Print results, including elapsed time System.out.println ("Elapsed time:" + (System.currentTimeMillis ()-start)); return "Done";}
Request this interface, and the console prints out the following:
Elapsed time: 0
2019-10-01 14 g.j.a.service.AsyncService 02VR 44.052 WARN 19051-[lTaskExecutor-4] g.j.a.service.AsyncService: My ThreadPoolTaskExecutor-4start this task!
2019-10-01 14 g.j.a.service.AsyncService 02VR 44.052 WARN 19051-[lTaskExecutor-3] g.j.a.service.AsyncService: My ThreadPoolTaskExecutor-3start this task!
2019-10-01 14 g.j.a.service.AsyncService 02VR 44.052 WARN 19051-[lTaskExecutor-2] g.j.a.service.AsyncService: My ThreadPoolTaskExecutor-2start this task!
2019-10-01 14 g.j.a.service.AsyncService 02VR 44.052 WARN 19051-[lTaskExecutor-1] g.j.a.service.AsyncService: My ThreadPoolTaskExecutor-1start this task!
2019-10-01 14 g.j.a.service.AsyncService 02VR 44.052 WARN 19051-[lTaskExecutor-6] g.j.a.service.AsyncService: My ThreadPoolTaskExecutor-6start this task!
2019-10-01 14 g.j.a.service.AsyncService 02VR 44.052 WARN 19051-[lTaskExecutor-5] g.j.a.service.AsyncService: My ThreadPoolTaskExecutor-5start this task!
You can see that the system returns the results directly to the user before the system really starts to perform the task.
At this point, the study on "Future pattern introduction and SpringBoot asynchronous programming example analysis" is over. I hope to be able to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.