“This is the 16th day of my participation in the August More Text Challenge. For details, see: August More Text Challenge.”

Let’s take a look at Spring Boot 2.x to understand the schedule of scheduled tasks

Based on the above code changes

Source: github.com/langyastudi…

Spring-fram /spring-fram…

Work often involves asynchronous tasks, usually using multi-threaded techniques such as a thread pool ThreadPoolExecutor, which executes as follows (image from the network) :

When developing with Spring, in addition to the @enableAsync and @Async annotations, you need to define a Bean of type TaskExecutor. Fortunately the Spring Boot TaskExecutionAutoConfiguration provides automatic configuration, It automatically registers a ThreadPoolTaskExecutor (TaskExecutor implementation class) for a Bean named applicationTaskExecutor, So in Spring Boot, you only need to use @enableAsync and @async annotations to complete multi-threaded asynchronous operations.

Using the step

Spring Boot provides asynchronous multi-threaded task functionality by:

  • @EnableAsync

    Enable support for asynchronous multithreaded tasks on the configuration class or Main class

  • @Async

    Annotate the asynchronous multithreaded tasks that need to be performed. It can be applied to a class or a method. All methods applied to a class are asynchronous.

Enable support for asynchronous multithreaded tasks in the entry class:

@SpringBootApplication
@EnableAsync
public class Application
{
    public static void main(String[] args)
    {... }}Copy the code

Define a class that contains asynchronous multithreaded tasks:

@Component
@Log4j2
public class AsyncTask
{
    @Async
    public void loopPrint(Integer i)
    {
        log.info("async task:"+ i); }}Copy the code

This is tested with CommandLineRunner:

@Bean
CommandLineRunner asyncTaskClr(AsyncTask asyncTask)
{
    return (args) -> {
        for (int ix=0; ix<10; ix++) { asyncTask.loopPrint(ix); }}; }Copy the code

The execution results of the program are as follows:

[task-1] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:0
[task-1] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:8
[task-1] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:9
[task-2] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:1
[task-3] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:2
[task-7] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:6
[task-6] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:5
[task-8] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:7
[task-5] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:4
[task-4] com.langyastudio.springboot.common.middleware.task.AsyncTask : async task:3
Copy the code

As you can see, instead of using the main thread, restartedMain, asynchronous tasks use a pool of eight threads with names beginning with task-. The execution results are out of order, which means that tasks are executed concurrently.

TaskExecutor

How to customize the thread pool information such as the number of threads and thread name prefix? The answer is ThreadPoolTaskExecutor, which allows you to customize information such as the number of threads, thread name prefixes, and so on for a specific asynchronous multithreaded task.

This way you can specify a ThreadPoolTaskExecutor for a specific task when there are multiple different asynchronous multi-threaded tasks on the system. Spring Boot provides the TaskExecutorBuilder Bean, which you can use to create our custom ThreadPoolTaskExecutor.

Example:

@Bean
ThreadPoolTaskExecutor customTaskExecutor(TaskExecutorBuilder builder)
{
    return builder.threadNamePrefix("langyatask")
            .corePoolSize(5)
            .build();
}
Copy the code

Specify a TaskExecutor in the comment for a multithreaded asynchronous task:

@Component
@Log4j2
public class AsyncTask
{
    @Async("customTaskExecutor")
    public void loopPrint(Integer i)
    {
        log.info("async task:"+ i); }}Copy the code

The number of threads, thread name prefix, and so on are executed according to the values defined by customTaskExecutor.

Future

Sometimes we want not only to execute tasks asynchronously, but also to have a return value when the task is completed. Java provides a generic Future interface to receive the result of the task execution. Spring Boot also provides support for this. Use classes such as AsyncResult that implement the ListenableFuture interface as vectors for the return value.

For example, if you want to return a value of type String, you can change the return value to:

@Async("customTaskExecutor")
public ListenableFuture<String> loopPrint(Integer i)
{
    String res = "async task:" + i;
    log.info(res);
    return new AsyncResult<>(res);
}
Copy the code

Call return value:

    @Autowired
    private AsyncTask asyncTask;

    // Block the call
    asyncTask.loopPrint(1).get(a);// Call for a limited time
    asyncTask.loopPrint(2).get(1, TimeUnit.SECONDS)
Copy the code

You can not use @Async in conjunction with lifecycle callbacks such as @PostConstruct. To asynchronously initialize Spring beans, you currently have to use a separate initializing Spring bean that then invokes the @Async annotated method on the target, as the following example shows:

public class SampleBeanImpl implements SampleBean {

    @Async
    void doSomething(a) {
        // ...}}public class SampleBeanInitializer {

    private final SampleBean bean;

    public SampleBeanInitializer(SampleBean bean) {
        this.bean = bean;
    }

    @PostConstruct
    public void initialize(a) { bean.doSomething(); }}Copy the code

Reference documents: Liao Xuefeng, “From enterprise development to Cloud Native Microservices: Spring Boot Combat”, etc