This is the 22nd day of my participation in the August More Text Challenge

Asynchronous tasks

concept

In SpringBoot, methods are annotated as asynchronous tasks using the @async annotation, and asynchronous tasks are submitted to run in a separate thread pool

use

  1. Using the @ Async

    @Slf4j
    @Component
    public class TestTaskFactory {
    
        /** * simulates a 5-second asynchronous task */
        @Async
        public Future<Boolean> asyncTask1(a) throws InterruptedException {
            doTask("asyncTask1".5);
            return new AsyncResult<>(Boolean.TRUE);
        }
    
        /** * simulates a 2-second asynchronous task */
        @Async
        public Future<Boolean> asyncTask2(a) throws InterruptedException {
            doTask("asyncTask2".2);
            return new AsyncResult<>(Boolean.TRUE);
        }
    
        /** * simulates a 3-second asynchronous task */
        @Async
        public Future<Boolean> asyncTask3(a) throws InterruptedException {
            doTask("asyncTask3".3);
            return new AsyncResult<>(Boolean.TRUE);
        }
    
        /** * simulates a 5-second synchronization task */
        public void task1(a) throws InterruptedException {
            doTask("task1".5);
        }
    
        /** * simulates a 2-second synchronization task */
        public void task2(a) throws InterruptedException {
            doTask("task2".2);
        }
    
        /** * simulates a 3-second synchronization task */
        public void task3(a) throws InterruptedException {
            doTask("task3".3);
        }
    
        private void doTask(String taskName, Integer time) throws InterruptedException {
            log.info("{} start execution, current thread name [{}]", taskName, Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(time);
            log.info("{} execute successfully, current thread name [{}]", taskName, Thread.currentThread().getName()); }}Copy the code
  2. The test class

    @Slf4j
    @SpringBootTest
    @EnableAsync
    public class TestTaskFactoryTest{
        @Autowired
        private TestTaskFactory taskFactory;
    
        /** * Test asynchronous task */
        @Test
        public void asyncTaskTest(a) throws InterruptedException, ExecutionException {
            long start = System.currentTimeMillis();
            Future<Boolean> asyncTask1 = taskFactory.asyncTask1();
            Future<Boolean> asyncTask2 = taskFactory.asyncTask2();
            Future<Boolean> asyncTask3 = taskFactory.asyncTask3();
            Call get() to block the main thread
            asyncTask1.get();
            asyncTask2.get();
            asyncTask3.get();
            long end = System.currentTimeMillis();
    
            log.info("All asynchronous tasks are completed, total time: {} ms", (end - start));
        }
    
        /** * Test synchronization task */
        @Test
        public void taskTest(a) throws InterruptedException {
            long start = System.currentTimeMillis();
            taskFactory.task1();
            taskFactory.task2();
            taskFactory.task3();
            long end = System.currentTimeMillis();
    
            log.info("All synchronization tasks are completed, total time: {} ms", (end - start)); }}Copy the code

The thread pool

  1. The thread pool interface for asynchronous tasks, TaskExecutor, inherits from JUC package executors

  2. TaskExecutor has many implementations in SpringBoot

    • SimpleAsyncTaskExecutor: No thread is reused, and a new thread is created for each call
    • SyncTaskExecutor: Executes tasks synchronously on the caller’s current thread, suitable for scenarios where multithreading is not required
    • ConcurrentTaskExecutor:ExecutorThe adaptation class is used to convert Java’sExecutorObjects are incorporated into Spring management
    • ThreadPoolTaskExecutor: common thread pool implementation, its essence is rightThreadPoolExecutorThe packaging, throughTaskExecutionAutoConfigurationPerform automatic configuration
  3. Configure an asynchronous task thread pool

Through the application.yaml file

You need to enable asynchronous tasks using the @EnableAsync annotation on the startup class or configuration class and configure the thread pool through the configuration file

spring:
  task:
    execution:
      pool:
        # Maximum number of threads
        max-size: 16
        Number of core threads
        core-size: 16
        # Survival time
        keep-alive: 10s
        # queue size
        queue-capacity: 100
        Whether to allow core threads to timeout
        allow-core-thread-timeout: true
      # thread name prefix
      thread-name-prefix: async-task-
Copy the code

Using the JavaConfig class

@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig implements AsyncConfigurer {

    /** * asynchronous task execution thread pool **@return* /
    @Bean(name = "asyncExecutor")
    public ThreadPoolTaskExecutor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setQueueCapacity(1000);
        executor.setKeepAliveSeconds(600);
        executor.setMaxPoolSize(20);
        executor.setThreadNamePrefix("async-task-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    @Override
    public Executor getAsyncExecutor() {
        return asyncExecutor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (throwable, method, objects) -> {
            log.error("Asynchronous task execution exception, message {}, method {}, params {}", throwable, method, objects); }; }}Copy the code

Timing task

concept

Annotate methods as Scheduled tasks using @scheduled, and SpringBoot will place the methods into the thread pool for execution on a Scheduled basis according to the configuration items in the annotations

use

  1. Using the @ Scheduled

    @Component
    @Slf4j
    public class TestTaskJob {
    
        /** * Execute */ every 10s
        @Scheduled(cron = "0/10 * * * * ?" )
        public void job1(a) {
            log.info([job1] start execution: {}, DateUtil.formatDateTime(new Date()));
        }
    
        /** * fixed interval */ is executed in 2s intervals starting from the boot time
        @Scheduled(fixedRate = 2000)
        public void job2(a) {
            log.info("[job2] start: {}", DateUtil.formatDateTime(new Date()));
        }
    
        /** * From the start time, the delay is 5s, and the interval is 4s * fixed waiting time */
        @Scheduled(fixedDelay = 4000, initialDelay = 5000)
        public void job3(a) {
            log.info("[job3] start execution: {}", DateUtil.formatDateTime(newDate())); }}Copy the code
  2. @ Scheduled parameters

    • Zone: the zone
    • FixedDelay: the number of milliseconds after the last execution
    • FixedRate: How many milliseconds have elapsed since the last execution started
    • InitialDelay: the number of milliseconds to delay the first execution
    • FixedDelayString, fixedRateString, initialDelayString: It is a string of characters. Placeholders can be used, for example${job.fixedDelay}
    • Corn: corn is an expression in the syntax[second] [minute] [hour] [day] [month] [week] [year]Years can be omitted

The thread pool

  1. The implementation of the scheduled task thread pool is ThreadPoolTaskScheduler, which wraps the JDK ScheduledExecutorService

  2. SchedulingConfiguration configuration class defines ScheduledAnnotationBeanPostProcessor the Bean, which scans the @ Scheduled annotations, and through the agent get method to create a thread to execute, submitted to the thread pool

  3. Thread pool configuration

    Through the application.yaml file

    You need to enable asynchronous tasks with the @enablesCheduling annotation on the startup class or configuration class and configure thread pools through the configuration file

    spring:
      task:
        scheduling:
          pool:
            size: 20
          thread-name-prefix: schedule-job-
    Copy the code

    Using the JavaConfig class

    @Configuration
    @EnableScheduling
    public class ExecutorConfig implements SchedulingConfigurer {
    
        /** * Thread pool used by scheduled tasks **@return* /
        @Bean(destroyMethod = "shutdown", name = "taskScheduler")
        public ThreadPoolTaskScheduler taskScheduler(a) {
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            scheduler.setPoolSize(10);
            scheduler.setThreadNamePrefix("schedule-task-");
            scheduler.setAwaitTerminationSeconds(600);
            scheduler.setWaitForTasksToCompleteOnShutdown(true);
            return scheduler;
        }
    
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { ThreadPoolTaskScheduler taskScheduler = taskScheduler(); scheduledTaskRegistrar.setTaskScheduler(taskScheduler); }}Copy the code