First, reading harvest

✔️1. Learn about the common single application periodic task framework

✔️2. Know how to use scheduled tasks in an individual

Download the source code of this chapter

👍 This chapter has been downloaded and shared on Github

Third, the Timer + TimerTask

  • This is the java.util.Timer class that comes with the JDK. This class allows you to schedule a java.util.TimerTask.
  • This allows your program to run at a certain frequency, but not at a specified time.
/ * * *@Description* This is the java.util.Timer class that allows you to schedule a java.util.TimerTask. * This allows your program to run at a certain frequency, but not at a specified time. Generally used less. *@Author: jianweil
 * @date: 2021/12/14 13:36
 */
public class TimerTest {
    public static void main(String[] args) {
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run(a) {
                System.out.println("task run:" + newDate()); }}; TimerTask timerTask2 =new TimerTask() {
            @Override
            public void run(a) {
                System.out.println("task2 run:" + new Date());
                // When multiple threads process timed tasks in parallel, the Timer runs multiple timetasks. If one of them does not catch an exception, the other tasks will terminate automatically. ScheduledExecutorService does not have this problem.
                int i = 1/0; }};// use ScheduledExecutorService instead of Timer
        Timer timer = new Timer();
        System.out.println("begin:" + new Date());
        // Schedule the specified task to start repeated fixed delay execution at the specified time. There is a 5 second delay to start execution and every 3 seconds after that
        timer.schedule(timerTask, 5000.3000);
        timer.schedule(timerTask2, 5000.3000); }}Copy the code
  • When multiple threads process timed tasks in parallel, when a Timer runs multiple timeTasks, other tasks are automatically terminated as long as one of them does not catch an exception. ScheduledExecutorService does not have this problem.

Four, ScheduledExecutorService

  • ScheduledExecutorService is also a built-in timing class of the JDK that can replace timers
package com.ljw.springboottimer.scheduledExecutorservice;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;

import java.util.Date;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/ * * *@Description: ScheduledExecutorService (JDK) * When a Timer runs multiple timetasks in parallel, if one of them does not catch an exception, the other tasks are automatically terminated. * ScheduledExecutorService does not have this problem. *@Author: jianweil
 * @date: 2021/12/14 13:42 * /
public class ScheduledExecutorServiceTest {
    public static void main(String[] args) throws InterruptedException {

        // When all non-daemon threads terminate, the program terminates, killing all daemon threads in the process. Conversely, the program does not terminate as long as any non-daemon threads are running.
        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1.new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(false).build());
        System.out.println("begin:" + new Date());
        // Parameters: 1. Task body 2. Delay time for first execution 3
        // The execution is delayed for 5 seconds, and then every 3 seconds
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run(a) {
                //do something
                System.out.println("begin:" + newDate()); }},5.3, TimeUnit.SECONDS); }}Copy the code

Five, the Spring Task

  • Spring provides classes that introduce dependencies:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
Copy the code
  • To enable a scheduled task: @enablescheduling
  • Use: Annotate @scheduled before the corresponding task method

5.1 Single-threaded serial execution -@Scheduled

  • The @scheduled annotation defaults to serial execution in the same thread, which is fine if there is only one Scheduled task, but when there are more Scheduled tasks, if one of them freezes, the rest of them won’t work.
  • Business test:
@Component
@EnableScheduling
public class SpringTaskTest {
    @Scheduled(cron = "0/5 * * * * *")
    public void run(a) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "=====>>>>> using cron {}" + (System.currentTimeMillis() / 1000)); }}Copy the code

5.2 Multi-Threaded Concurrent running -@Scheduled+ Configure the program pool of the timer (recommended)

  • To solve the problem of single-thread serial execution of tasks, you need to configure the program pool of timer. This method is recommended

  • Configure and inject a TaskScheduler class bean

  • The thread pool class for configuring timers is as follows:

package com.ljw.springboottimer.springtask;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

/ * * *@Description: solve single thread serial execution mode 2:@Scheduled+ Configure the timer thread pool *@Author: jianweil
 * @date: 2021/12/14 14:44
 */
@Configuration
public class TaskSchedulerConfig {
    /** * Initializes a TaskScheduler with a pool size of 5, avoiding a single thread for all tasks **@return* /
    @Bean
    public TaskScheduler taskScheduler(a) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(5);
        taskScheduler.setThreadNamePrefix("TaskSchedulerConfig-ljw");
        returntaskScheduler; }}Copy the code
  • Business test
@Component
@EnableScheduling
public class SpringTaskTest {

    @Scheduled(cron = "0/5 * * * * *")
    public void run(a) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "=====>>>>> using cron {}" + (System.currentTimeMillis() / 1000));
    }
    
    @Scheduled(fixedRate = 5000)
    public void run1(a) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "=====>>>>> using fixedRate {}" + (System.currentTimeMillis() / 1000)); }}Copy the code

5.3 Multi-Threaded Concurrent Execution -@Scheduled+ @async + Configure an asynchronous thread pool

  • To solve the problem of single-thread serial execution of tasks, it can also be combined with asynchronous annotation @async implementation, but this method is not recommended, need two annotations, code writing workload
  • It can also solve the problem that fixedRate has to wait for the last task to complete when the next task is executed after the configured interval, which is not solved by 3.2.
  • Configure the asynchronous thread pool class as follows:
package com.ljw.springboottimer.springtask;

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;
import java.util.concurrent.ThreadPoolExecutor;

/ * * *@Description: solve single thread serial execution mode 1:@Scheduled+@Async+ Configure asynchronous thread pool *@Author: jianweil
 * @date: 2021/12/14 * / desire
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    / * * * definition@AsyncThe default thread pool * ThreadPoolTaskExecutor is not a fully IOC container-managed bean and can be added to methods@BeanThe annotation is passed to the container manager to remove the taskExecutor.initialize() method call, which is automatically called by the container@return* /
    @Override
    public Executor getAsyncExecutor(a) {
        int processors = Runtime.getRuntime().availableProcessors();
        // Common actuators
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // Number of core threads
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        // Maximum number of threads in the queue. Default: 50
        taskExecutor.setQueueCapacity(100);
        // Thread name prefix
        taskExecutor.setThreadNamePrefix("AsyncConfig-ljw-");
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // Perform initialization (critical)
        taskExecutor.initialize();
        returntaskExecutor; }}Copy the code
  • Business tests require the @async annotation
@Component
@EnableScheduling
public class SpringTaskTest {

    @Scheduled(cron = "0/5 * * * * *")
    @Async
    public void run(a) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "=====>>>>> using cron {}" + (System.currentTimeMillis() / 1000));
    }
    
    @Scheduled(fixedRate = 5000)
    @Async
    public void run1(a) throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "=====>>>>> using fixedRate {}" + (System.currentTimeMillis() / 1000)); }}Copy the code
  • If the program pool of 3.2 Configuring timers and 3.3 Configuring asynchronous thread Pools are configured, and @scheduled + @async annotations are used, the thread pool used by Scheduled tasks is: Configuring asynchronous thread pools

5.4 @Scheduled parameter parsing

  • Cron: The cron expression is used to configure the task execution time (default is fixedDelay)
  • InitialDelay: Defines how long the task should be delayed before the first execution
  • FixedRate: Defines a scheduled task that executes at a certain frequency. After each task is completed, fixedRate looks for the next task to be executed from the task scheduling table and determines whether it is time to execute it. No matter how long the execution time of a fixedRate task is, two task instances will not be executed at the same time. It also waits until the last task is completed and determines whether it is time to execute it. Make methods asynchronous, as described in Step 5.3, unless the @async annotation is used. (5.2 is configuring the thread pool, which fails to achieve the effect)
  • FixedDelay: Defines a scheduled task that executes at a certain frequency. FixedDelay is always delayed for a fixed amount of time after the completion of the previous task before executing the next task

Six, Quartz

When developing Quartz related applications, a scheduled scheduling capability can be implemented as long as Job, JobDetail, Trigger and Scheduler are defined.

If SpringBoot is later than 2.0.0, then the quart dependency is already included in the spring-boot-starter, so you can introduce the dependency directly:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
Copy the code

6.1. Create a Task Class

  • Method 1: Implement the Execute method of the Job class to implement a task (recommended)
  • Task 1 is as follows:
package com.ljw.springboottimer.quartz.do1;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;

/ * * *@Description: My scheduled task - Method 1 *@Author: jianweil
 * @date: 2021/12/14 16:06 * /
public class MyTaskService1 implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println(Thread.currentThread().getName() + "------ Job ------" + newDate()); }}Copy the code
  • Method 2: Inherit the QuartzJobBean class rewrite method to implement a task
  • Task 2 is as follows:
package com.ljw.springboottimer.quartz.do1;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.Date;

/ * * *@Description: My scheduled task - Method 2 *@Author: jianweil
 * @date: 2021/12/14 16:06 * /
public class MyTaskService2 extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println(Thread.currentThread().getName() + "---QuartzJobBean-----" + newDate()); }}Copy the code

6.2. Configure task descriptions and triggers

  • The configuration class declares two beans for each task
    • 1.JobDetail
    • 2.
  • Use SimpleScheduleBuilder or CronScheduleBuilder to configure scheduler information
package com.ljw.springboottimer.quartz.do1;

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Date;

/ * * *@Description: Two steps are required for each task * 1. Configure Trigger Trigger *@Author: jianweil
 * @date: 2021/12/14 16:08 * /
@Configuration
public class QuartzConfig {

    /** * Create JobDetail1 ** for task 1@return* /
    @Bean
    public JobDetail teatQuartzDetail1(a) {
        return JobBuilder.newJob(MyTaskService1.class)
                / / the description of the job
                .withDescription("this is a job1")
                // Job name and group
                .withIdentity("myTrigger1"."myTriggerGroup1")
                .storeDurably().build();
    }

    /** * Create JobDetail2 ** for task 2@return* /
    @Bean
    public JobDetail teatQuartzDetail2(a) {
        return JobBuilder.newJob(MyTaskService2.class)
                / / the description of the job
                .withDescription("this is a job2")
                // Job name and group
                .withIdentity("myTrigger2"."myTriggerGroup2")
                .storeDurably().build();
    }

    /** * create task 1 Trigger1 **@return* /
    @Bean
    public Trigger testQuartzTrigger1(a) {
        // Use SimpleScheduleBuilder or CronScheduleBuilder
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                // Set the time period in seconds
                .withIntervalInSeconds(10)
                .repeatForever();

        // Execute once in two seconds, Quartz expression, support all kinds of cool expressions
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/3 * * * *?");
        SimpleSchedle trigger is valid. The task starts after 3 seconds
        long time = System.currentTimeMillis() + 3 * 1000L;
        Date statTime = new Date(time);


        return TriggerBuilder.newTrigger()
                .withDescription("")
                .forJob(teatQuartzDetail1())
                .withIdentity("myTrigger1"."myTriggerGroup1")
                // Start at the current time by default
                .startAt(statTime)
                .withSchedule(cronScheduleBuilder)
                //.withSchedule(scheduleBuilder)
                .build();

    }

    /** * Create task 2 Trigger2 **@return* /
    @Bean
    public Trigger testQuartzTrigger2(a) {
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                // Set the time period in seconds
                .withIntervalInSeconds(10)
                .repeatForever();
        return TriggerBuilder.newTrigger()
                .forJob(teatQuartzDetail2())
                .withIdentity("myTrigger2"."myTriggerGroup2") .withSchedule(scheduleBuilder) .build(); }}Copy the code
  • 👍🏻 : have harvest, praise encouragement!
  • ❤️ : Collect articles, easy to look back!
  • 💬 : Comment exchange, mutual progress!