Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the method of Spring asynchronous task

2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the knowledge of "what is the method of Spring asynchronous task". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Since the mail sending process is not a critical node for registration, we can send the message for asynchronous execution to reduce the execution time of the registration method.

We can create our own thread pool and then perform asynchronous tasks. The sample code is as follows:

/ / Best practices for production using thread pools: be sure to customize the thread pool and do not find it troublesome to create a thread pool using Executors private ThreadPoolExecutor threadPool = new ThreadPoolExecutor (5,10,60l, TimeUnit.SECONDS, new LinkedBlockingDeque (200), new ThreadFactoryBuilder (). SetNameFormat ("register-%d"). Build ()) / * use thread pool to perform the task of sending mail * / private void sendEmailByThreadPool () {threadPool.submit (()-> emailService.sendEmail ());}

Ps: the best practice of using thread pool in production is to customize the thread pool, set reasonable thread pool parameters according to the business scenario, and set a clear prefix for the thread, so that it is very easy to troubleshoot the problem.

Never use Executors-related methods to create thread pools for convenience.

The above code uses the thread pool to complete the asynchronous task of sending mail. You can see that this example is still a bit troublesome. We not only need to customize the thread pool, but also need to create the relevant task execution class.

Spring provides the ability to perform asynchronous tasks, which we can easily do with an annotation.

Today, A Fan will explain how to use Spring asynchronous tasks, as well as some points for attention in the use of Spring asynchronous tasks.

How asynchronous tasks are used

The Spring asynchronous task needs to set the @ Async annotation on the relevant methods. Here, to give an example, we create an EmailService class that specializes in completing the mail service.

The code is as follows:

@ Slf4j @ Service public class EmailService {/ * Asynchronous sending task * * @ throws InterruptedException * / @ SneakyThrows @ Async public void sendEmailAsync () {log.info ("example of sending mail using Spring asynchronous task"); / / simulating email sending time TimeUnit.SECONDS.sleep (2l);}}

Note here that the Spring asynchronous task is turned off by default, so we need to use @ EnableAsync to open the asynchronous task.

If you are still using the Spring XML configuration, we need to configure the following configuration:

After the above configuration is complete, we only need to inject the EmailService into the caller, such as the previous Controller, and then call the method directly, which will be executed in the asynchronous thread.

@ Slf4j @ RestController public class RegisterController {@ Autowired EmailService emailService; @ RequestMapping ("register") public String register () {log.info ("registration process starts"); emailService.sendEmailAsync (); return "success";}}

The output log is as follows:

As you can see from the log, the two method execution threads are different, which indicates that the EmailService#sendEmailAsync was successfully executed by the asynchronous thread.

Asynchronous task with return value

The above asynchronous task is relatively simple, but sometimes we need to get the return value of the asynchronous task.

If we use the thread pool to perform asynchronous tasks, we can use threadPool#submit to get the return object Future, and then we can call the get method inside it to get the return result.

In the Spring asynchronous task, we can also use Future to get the returned result. The sample code is as follows:

@ Async @ SneakyThrows public Future sendEmailAsyncWithResult () {log.info ("send mail using Spring asynchronous task and get the result returned by the task"); TimeUnit.SECONDS.sleep (21); return AsyncResult.forValue ("success");}

Note here that we need to use the Spring inner class AsyncResult to return the object here.

The Controller layer invocation code is as follows:

Private void sendEmailWithResult () {Future future = emailService.sendEmailAsyncWithResult (); try {String result = future.get ();} catch (InterruptedException e) {e.printStackTrace ();} catch (ExecutionException e) {e.printStackTrace ();}

We know that the Future#get method will block until the asynchronous task executes successfully.

Sometimes we get the return value of the asynchronous task to do some follow-up business, but the main process method is that there is no need to return the return value of the asynchronous task. If we use the Future#get method, the main process will always be blocked.

For this scenario, we can use org.springframework.util.concurrent.ListenableFuture to slightly modify the above method.

The class ListenableFuture allows us to register the callback function, which will be executed immediately as soon as the asynchronous task executes successfully or an exception is executed. In this way, there is no need to block the main thread of execution.

The sample code is as follows:

@ Async @ SneakyThrows public ListenableFuture sendEmailAsyncWithListenableFuture () {log.info ("send mail using Spring asynchronous task and get the result returned by the task"); TimeUnit.SECONDS.sleep (21); return AsyncResult.forValue ("success");}

The Controller layer code is as follows:

ListenableFuture listenableFuture = emailService.sendEmailAsyncWithListenableFuture (); / / Asynchronous callback handling listenableFuture.addCallback (new SuccessCallback () {@ Override public void onSuccess (String result) {log.info ("Asynchronous callback processing return value");}}, new FailureCallback () {@ Override public void onFailure (Throwable ex) {log.error ("Asynchronous callback handling exception", ex);}})

See here, if some students are confused, we return the object is AsyncResult, why the method return class can be Future, can also be ListenableFuture?

After reading this class inheritance relationship, you should know the answer.

Exception handling mode

Exception handling in asynchronous tasks is not very difficult, we just need to try...catch the entire block of code in the method.

Try {/ / other code} catch (Exception e) {e.printStackTrace ();}

Generally speaking, we only need to catch Exception exceptions to deal with most situations.

But in extreme cases, such as when an OOM occurs within a method, an OutOfMemoryError will be thrown. If an Error error occurs, the above capture code will be invalidated.

Spring's asynchronous tasks provide several exception handling methods by default, which can uniformly handle exceptions that occur in asynchronous tasks.

Exception handling with return value

If we use an asynchronous task with a return value, it's easier to handle it, and we just need to catch the exception thrown by Future#get.

Future future = emailService.sendEmailAsyncWithResult (); try {String result = future.get ();} catch (InterruptedException e) {e.printStackTrace ();} catch (ExecutionException e) {e.printStackTrace ();}

If we use ListenableFuture to register the callback function to handle, we add a FailureCallback to the method and handle the relevant exceptions in this implementation class.

ListenableFuture listenableFuture = emailService.sendEmailAsyncWithListenableFuture (); / / Asynchronous callback handling listenableFuture.addCallback (new SuccessCallback () {@ Override public void onSuccess (String result) {log.info ("Asynchronous callback handling return value");} / / exception handling}, new FailureCallback () {@ Override public void onFailure (Throwable ex) {log.error ("Asynchronous callback handling exception", ex) })

Unified exception handling

It is more complicated to handle asynchronous tasks without return values. We need to inherit AsyncConfigurerSupport and implement the getAsyncUncaughtExceptionHandler method. The sample code is as follows:

@ Slf4j @ Configuration public class AsyncErrorHandler extends AsyncConfigurerSupport {@ Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler () {AsyncUncaughtExceptionHandler handler = (throwable, method, objects)-> {log.error (Global exception capture, throwable);}; return handler;}}

Ps: this exception handling can only handle asynchronous tasks without a return value.

Pay attention to the use of asynchronous tasks

Asynchronous thread pool settings

The Spring asynchronous task defaults to the Spring internal thread pool SimpleAsyncTaskExecutor.

This thread pool is crappy and does not reuse threads. That is, if you make a request, a new thread will be created. In extreme cases, if too many calls are made, a large number of threads will be created.

Threads in Java will take up a certain amount of memory space, so creating a large number of threads will result in OOM errors.

So if we need to use asynchronous tasks, we need to replace the default thread pool with a custom thread pool.

XML configuration mode

If we are currently using Spring XML configuration, we can set up the thread pool with the following configuration:

Annotation mode

If the annotation method is configured, the configuration is as follows:

@ Configuration public class AsyncConfiguration {@ Bean public ThreadPoolTaskExecutor taskExecutor () {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor (); executor.setThreadNamePrefix ("task-Executor-"); executor.setMaxPoolSize (10); executor.setCorePoolSize (5); executor.setQueueCapacity (200); / / there are other parameters that can be set return executor;}}

As long as we configure this thread pool Bean,Spring 's asynchronous tasks will be executed using this thread pool.

If our application is configured with multiple thread pools Bean, asynchronous tasks need to be specified to be executed using a thread pool, and we just need to set the name of the corresponding Bean on the @ Async annotation. The sample code is as follows:

@ Async ("taskExecutor") public void sendEmailAsync () {log.info ("sample sending mail using Spring asynchronous task"); TimeUnit.SECONDS.sleep (21);}

Spring Boot mode

If it is a SpringBoot project, according to Ah Fan's test, the default number of core threads is 8, the maximum number of threads is Integer.MAX_VALUE, and the number of queues is also Integer.MAX_ value thread pool.

Although the above thread pool does not have to worry about creating too many threads, it is still possible that there are too many queue tasks, leading to OOM problems. So it is still recommended to use a custom thread pool, or modify the default configuration in the configuration file, for example:

Spring.task.execution.pool.core-size=10 spring.task.execution.pool.max-size=20 spring.task.execution.pool.queue-capacity=200

Ps: if we customize a thread pool using annotations, then all Spring asynchronous tasks will use this thread pool. Thread pools created through the SpringBoot profile will be invalidated.

Asynchronous method failure

The principle behind the Spring asynchronous task is to use AOP, and when using Spring AOP, we need to be careful not to call other methods that use AOP inside the method, which may be a bit of a mouthful. Let's take a look at the code:

When @ Async @ SneakyThrows public ListenableFuture sendEmailAsyncWithListenableFuture () {/ / is called like this, sendEmailAsync will not execute sendEmailAsync () asynchronously; log.info ("use Spring asynchronous task to send mail and get the result returned by the task"); TimeUnit.SECONDS.sleep (2l); return AsyncResult.forValue ("success") } / * Asynchronous sending task * * @ throws InterruptedException * / @ SneakyThrows @ Async ("taskExecutor") public void sendEmailAsync () {log.info ("sending mail sample using Spring asynchronous task"); TimeUnit.SECONDS.sleep (2l);}

The above two methods are in the same class, so the call will invalidate the AOP and fail to have the effect of AOP.

Other similar @ Transactional, as well as custom AOP annotations will have this problem, you should pay attention to this point in the process.

This is the end of the content of "what is the method of Spring asynchronous task". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

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.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report