Scheduled ThreadPoolExecutor, Timer, @Scheduled and Quartz for scheduled tasks in Java

1 Introduction

In practical applications, sometimes we need to create some delayed and periodic tasks. For example, we want to log every hour after our program starts and clean it up at 12 o'clock every day. Expired data in the database, etc. The JDK provides two methods to create delayed periodic tasks. They are ScheduledThreadPoolExecutor and Timer respectively. There is also an open source more powerful task scheduling framework Quartz. Let’s take a closer look at these three frameworks.


2.Timer

The main methods of Timer are:

// 安排在指定的时间执行
void schedule(TimerTask task, Date time);

// 安排在指定的时间开始以重复的延时执行
void schedule(TimerTask task, Date firstTime, long period);

// 安排在指定的延迟后执行
void schedule(TimerTask task, long delay);

// 安排在指定的延迟后开始以重复的延时执行
void schedule(TimerTask task, long delay, long period);

// 安排在指定的时间开始以重复的速率执行
void scheduleAtFixedRate(TimerTask task, Date firstTime, long period);

// 安排在指定的延迟后开始以重复的速率执行
void scheduleAtFixedRate(TimerTask task, long delay, long period);

//可以在任何时刻调用cancel方法终止timer线程
cancel();

//从任务队列中删除已取消的任务,返回删除的数量
int purge();

Note: The difference between repeated delay and repeated rate is that the former starts the next execution after the execution of the previous task is completed in period time; while scheduleAtFixedRate will try to execute the interval according to the initial time of the task. . If the execution of a task is delayed for some reason, subsequent tasks scheduled using schedule() will also be delayed, and using scheduleAtFixedRate() will quickly start two or more executions, so that the execution time of the subsequent tasks can be catch up.


3.ScheduledThreadPoolExecutor

**Main method of ScheduledThreadPoolExecutor:
 

// 在指定的延迟后执行
<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)

// 在指定的延迟后执行
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)

// 在指定的延迟后以固定速率执行
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

// 在指定的延迟后以固定间隔执行
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

Regarding ScheduledThreadPoolExecutor, I have described it in detail in the thread pool article. You can refer to the thread pool in Java.

If you want to use scheduled tasks in the JDK, it is recommended to use ScheduledThreadPoolExecutor instead of Timer.


4. Scheduled tasks in Spring @Scheduled

Spring Task is not an independent project. It is a scheduled task tool provided under the spring-context module. It is a task that comes with Spring 3.0 and later. It can be regarded as a lightweight Quartz.

There are two ways to use Spring Task, one is based on the annotation ****@Scheduled, and the other is based on the configuration file. It is recommended to use annotations and configuration classes in springboot. Here we mainly use annotations and configuration classes, and demos based on configuration files will also be given.

Based on annotations

Enable it by annotating @EnableScheduling on the springboot startup class. Then use the @Scheduled annotation on the class method. The code example is as follows:

@Component
public class ScheduleTest {


    @Scheduled(fixedDelayString = "5000")
   public void testFixedDelayString() {
        System.out.println("Execute at " + System.currentTimeMillis());
    }
}

For the use of annotations, please refer to my previous article, which is very detailed: The use of @scheduled annotations

Based on xml configuration

The first is the task class:

public class SpringTask {

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public void m1(){
        System.out.println("m1:"+simpleDateFormat.format(new Date()));
    }

    public void m2(){
        System.out.println("m2:"+simpleDateFormat.format(new Date()));
    }

    public void m3(){
        System.out.println("m2:"+simpleDateFormat.format(new Date()));
    }
}

Then the xml configuration:

<!--spring-task.xml配置-->
<bean id="springTask" class="com.njit.springtask.SpringTask"></bean>
   <!--注册调度任务-->
   <task:scheduled-tasks>
       <!--延迟8秒 执行任务-->
       <!--<task:scheduled ref="springTask" method="m1" fixed-delay="8000" />-->

       <!--固定速度5秒 执行任务-->
       <!--<task:scheduled ref="springTask" method="m2" fixed-rate="5000"/>-->

       <!--
           使用cron表达式 指定触发时间
           spring task 只支持6位的cron表达式 秒 分 时 日 月 星期
       -->
       <task:scheduled ref="springTask" method="m3" cron="50-59 * * ? * *"/>
   </task:scheduled-tasks>

   <!--执行器配置-->
   <task:executor id="threadPoolTaskExecutor" pool-size="10" keep-alive="5"></task:executor>

   <!--调度器配置-->
   <task:scheduler id="threadPoolTaskScheduler" pool-size="10"></task:scheduler>

Spring Task task executor and scheduler explanation

Implementation principle

Spring task has two abstractions for scheduled tasks:

TaskExecutor: Same as Executor in jdk. The purpose of introduction is to provide thread pool support for the execution of scheduled tasks. If ** is not set, there is only one thread by default. **

TaskScheduler: Provides scheduled task support. You need to pass in a Runnable task as a parameter and specify the time or trigger that needs to be executed periodically, so that the Runnable task can be executed periodically.

The inheritance relationship is as follows:

The implementation classes of task executor and scheduler are ThreadPoolTaskExecutor and ThreadPoolTaskScheduler respectively.

TaskScheduler needs to pass in a Runnable task as a parameter and specify the time or trigger that needs to be executed periodically.

Spring defines the implementation class CronTrigger of the Trigger interface, which supports the use of cron expressions to specify timing strategies, as follows:

scheduler.schedule(task, new CronTrigger("30 * * * * ?"));

In springboot projects, we generally use the @schedule annotation to use spring tasks. The internal implementation of this annotation is to use the above content.

After spring initializes the bean, it intercepts all methods using the **@Scheduled** annotation through postProcessAfterInitialization, parses the corresponding annotation parameters, and puts them into the "scheduled task list" for subsequent processing; then "scheduled task list" Unified execution of corresponding scheduled tasks (tasks are executed sequentially, cron is executed first, and then fixedRate is executed)


For specific source code analysis, please refer to: Scheduling module @Schedule annotation source code analysis in Spring Summary Single-threaded and
multi
-threaded issues of scheduled tasks @Scheduled

SpringBoot uses @scheduled to execute tasks regularly in a single thread. If there are multiple tasks and one task takes too long to execute, it may cause other subsequent tasks to be blocked until the task is completed. This will create the illusion that some tasks cannot be executed on time.

You can test it with the following code:

@Scheduled(cron = "0/1 * * * * ? ")
public void deleteFile() throws InterruptedException {     log.info("111delete success, time:" + new Date().toString());     Thread.sleep( 1000 * 5);//Simulate long-term execution, such as IO operations, http requests } @Scheduled(cron = "0/1 * * * * ? ") public void syncFile() {     log.info("222sync success, time :" + new Date().toString()); }



 



2021-08-25 23:38:27.008  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:38:27 CST 2021
2021-08-25 23:38:32.010  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:38:32 CST 2021
2021-08-25 23:38:33.004  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:38:33 CST 2021
2021-08-25 23:38:38.007  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:38:38 CST 2021
2021-08-25 23:38:39.007  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:38:39 CST 2021
2021-08-25 23:38:44.014  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:38:44 CST 2021
2021-08-25 23:38:45.015  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:38:45 CST 2021
2021-08-25 23:38:50.027  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:38:50 CST 2021
2021-08-25 23:38:51.001  INFO 18972 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:38:51 CST 2021

It can be clearly seen in the log above that syncFile is blocked and is not executed until deleteFile is executed. Moreover, it
can also be seen from the log information that @Scheduled uses a single thread in a thread pool to perform all tasks.

/**If Thread.sleep(1000*5) is commented out, the output will be as follows:

2021-08-25 23:40:12.003  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:40:12 CST 2021
2021-08-25 23:40:12.004  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:40:12 CST 2021
2021-08-25 23:40:13.015  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:40:13 CST 2021
2021-08-25 23:40:13.015  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:40:13 CST 2021
2021-08-25 23:40:14.015  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:40:14 CST 2021
2021-08-25 23:40:14.015  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:40:14 CST 2021
2021-08-25 23:40:15.011  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:40:15 CST 2021
2021-08-25 23:40:15.011  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:40:15 CST 2021
2021-08-25 23:40:16.005  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:40:16 CST 2021
2021-08-25 23:40:16.005  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:40:16 CST 2021
2021-08-25 23:40:17.002  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 111delete success, time:Wed Aug 25 23:40:17 CST 2021
2021-08-25 23:40:17.002  INFO 17988 --- [   scheduling-1] com.njit.springtask.ScheduleTest         : 222sync success, time:Wed Aug 25 23:40:17 CST 2021

View the source code, starting from the ScheduledAnnotationBeanPostProcessor class and working your way down. Sure enough, there is another judgment like this in ScheduleTasks in ScheduledTaskRegistrar (scheduled task registration class):

if (this.taskScheduler == null) {
    this.localExecutor = Executors.newSingleThreadScheduledExecutor();
    this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}

This means that if taskScheduler is empty, then a single-threaded thread pool will be created for the scheduled task. There is also a method to set taskScheduler in this class:

public void setScheduler(Object scheduler) {
    Assert.notNull(scheduler, "Scheduler object must not be null");
    if (scheduler instanceof TaskScheduler) {
        this.taskScheduler = (TaskScheduler) scheduler;
    }
    else if (scheduler instanceof ScheduledExecutorService) {
        this.taskScheduler = new ConcurrentTaskScheduler(((ScheduledExecutorService) scheduler));
    }
    else {
        throw new IllegalArgumentException("Unsupported scheduler type: " + scheduler.getClass());
    }
}

Solution

    1. Expand the number of core threads in the original scheduled task thread pool

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(50));
    }
}

In this method, after the program is started, 50 threads will be gradually started and placed in the thread pool. Each scheduled task will occupy 1 thread each time it is executed. But the same scheduled task is still executed in the same thread.
For example, when the program starts, each scheduled task occupies one thread. Task 1 starts executing, and task 2 also starts executing. If task 1 is stuck, then in the next cycle, task 1 will still be stuck, and task 2 can be executed normally. In other words, if task 1 is stuck at a certain time, it will not affect other threads, but its own scheduled task will always wait for the completion of the last task!

After configuring as above, start the task

@Component
@Slf4j
public class ScheduleTest {


    @Scheduled(cron = "0/1 * * * * ? ")
    public void deleteFile() throws InterruptedException {         log.info(Thread.currentThread().getName()+" thread 1111111delete success, time: " + new Date( ).toString());         Thread.sleep(1000 * 10); //Simulate long-term execution, such as IO operations, http requests     }


    @Scheduled(cron = "0/1 * * * * ? ")
    public void syncFile() throws InterruptedException {         log.info(Thread.currentThread().getName()+" thread 22222222sync success, time: " + new Date( ).toString());         Thread.sleep(1000 * 10);//Simulate long-term execution, such as IO operations, http requests     } }



The log is as follows:

2021-08-26 22:54:58.006  INFO 1776 --- [pool-1-thread-2] com.njit.springtask.ScheduleTest         : pool-1-thread-2  线程 1111111delete success, time:Thu Aug 26 22:54:58 CST 2021
2021-08-26 22:54:58.006  INFO 1776 --- [pool-1-thread-1] com.njit.springtask.ScheduleTest         : pool-1-thread-1  线程 22222222sync success, time:Thu Aug 26 22:54:58 CST 2021
2021-08-26 22:55:09.003  INFO 1776 --- [pool-1-thread-1] com.njit.springtask.ScheduleTest         : pool-1-thread-1  线程 22222222sync success, time:Thu Aug 26 22:55:09 CST 2021
2021-08-26 22:55:09.003  INFO 1776 --- [pool-1-thread-2] com.njit.springtask.ScheduleTest         : pool-1-thread-2  线程 1111111delete success, time:Thu Aug 26 22:55:09 CST 2021
2021-08-26 22:55:20.005  INFO 1776 --- [pool-1-thread-3] com.njit.springtask.ScheduleTest         : pool-1-thread-3  线程 1111111delete success, time:Thu Aug 26 22:55:20 CST 2021
2021-08-26 22:55:20.005  INFO 1776 --- [pool-1-thread-4] com.njit.springtask.ScheduleTest         : pool-1-thread-4  线程 22222222sync success, time:Thu Aug 26 22:55:20 CST 2021
2021-08-26 22:55:31.004  INFO 1776 --- [pool-1-thread-2] com.njit.springtask.ScheduleTest         : pool-1-thread-2  线程 1111111delete success, time:Thu Aug 26 22:55:31 CST 2021
2021-08-26 22:55:31.004  INFO 1776 --- [pool-1-thread-1] com.njit.springtask.ScheduleTest         : pool-1-thread-1  线程 22222222sync success, time:Thu Aug 26 22:55:31 CST 2021
2021-08-26 22:55:42.011  INFO 1776 --- [pool-1-thread-3] com.njit.springtask.ScheduleTest         : pool-1-thread-3  线程 1111111delete success, time:Thu Aug 26 22:55:42 CST 2021
2021-08-26 22:55:42.011  INFO 1776 --- [pool-1-thread-6] com.njit.springtask.ScheduleTest         : pool-1-thread-6  线程 22222222sync success, time:Thu Aug 26 22:55:42 CST 2021
2021-08-26 22:55:53.002  INFO 1776 --- [pool-1-thread-4] com.njit.springtask.ScheduleTest         : pool-1-thread-4  线程 1111111delete success, time:Thu Aug 26 22:55:53 CST 2021
2021-08-26 22:55:53.002  INFO 1776 --- [pool-1-thread-7] com.njit.springtask.ScheduleTest         : pool-1-thread-7  线程 22222222sync success, time:Thu Aug 26 22:55:53 CST 2021
2021-08-26 22:56:04.002  INFO 1776 --- [pool-1-thread-8] com.njit.springtask.ScheduleTest         : pool-1-thread-8  线程 22222222sync success, time:Thu Aug 26 22:56:04 CST 2021
2021-08-26 22:56:04.002  INFO 1776 --- [pool-1-thread-5] com.njit.springtask.ScheduleTest         : pool-1-thread-5  线程 1111111delete success, time:Thu Aug 26 22:56:04 CST 2021
2021-08-26 22:56:15.006  INFO 1776 --- [pool-1-thread-1] com.njit.springtask.ScheduleTest         : pool-1-thread-1  线程 1111111delete success, time:Thu Aug 26 22:56:15 CST 2021
2021-08-26 22:56:15.006  INFO 1776 --- [pool-1-thread-2] com.njit.springtask.ScheduleTest         : pool-1-thread-2  线程 22222222sync success, time:Thu Aug 26 22:56:15 CST 2021
2021-08-26 22:56:26.001  INFO 1776 --- [pool-1-thread-9] com.njit.springtask.ScheduleTest         : pool-1-thread-9  线程 1111111delete success, time:Thu Aug 26 22:56:26 CST 2021
2021-08-26 22:56:26.001  INFO 1776 --- [ool-1-thread-10] com.njit.springtask.ScheduleTest         : pool-1-thread-10  线程 22222222sync success, time:Thu Aug 26 22:56:26 CST 2021
2021-08-26 22:56:37.016  INFO 1776 --- [pool-1-thread-6] com.njit.springtask.ScheduleTest         : pool-1-thread-6  线程 22222222sync success, time:Thu Aug 26 22:56:37 CST 2021
2021-08-26 22:56:37.016  INFO 1776 --- [pool-1-thread-3] com.njit.springtask.ScheduleTest         : pool-1-thread-3  线程 1111111delete success, time:Thu Aug 26 22:56:37 CST 2021
2021-08-26 22:56:48.014  INFO 1776 --- [ool-1-thread-11] com.njit.springtask.ScheduleTest         : pool-1-thread-11  线程 1111111delete success, time:Thu Aug 26 22:56:48 CST 2021

    2. Configure Scheduled for multi-thread execution

@Configuration
public class ScheduleConfig {
 
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(50);
        return taskScheduler;
    }
}

@EnableScheduling
public class TaskFileScheduleService {
 
    @Scheduled(cron="0 */1 * * * ?")
    public void task1(){
    .......
    }
    
    @Scheduled(cron="0 */1 * * * ?")
    public void task2(){
    .......
    }

In this method, the program starts and each scheduled task occupies one thread. Task 1 starts executing, and task 2 also starts executing. If task 1 is stuck, then in the next cycle, task 1 will still be stuck, and task 2 can be executed normally. In other words, if task 1 is stuck at a certain time, it will not affect other threads, but its own scheduled task will always wait for the completion of the last task! This solution performs the same as the first one!

    3. Use @Async annotation

@Configuration
@EnableAsync
public class ScheduleConfig {

}

@EnableScheduling
public class TaskFileScheduleService {
 
    @Async
    @Scheduled(cron="0 */1 * * * ?")
    public void task1(){
    .......
    }
    
    @Async
    @Scheduled(cron="0 */1 * * * ?")
    public void task2(){
    .......
    }

In this method, every time the scheduled task is started, a separate thread will be created for processing. In other words, the same scheduled task will also start multiple threads for processing.
For example: Task 1 and Task 2 are processed together, but thread 1 is stuck, but task 2 can be executed normally. And in the next cycle, task 1 will still be executed normally, and task 1 will not be affected because it was stuck last time.
However, there are more and more stuck threads in Task 1, and the thread pool will eventually be filled up, which will still affect the scheduled tasks. (@Async asynchronous method uses Spring to create ThreadPoolTaskExecutor by default. Default number of core threads: 8, maximum number of threads: Integet.MAX_VALUE, queue uses LinkedBlockingQueue, capacity: Integet.MAX_VALUE, idle thread retention time: 60s, thread pool rejection policy: AbortPolicy .)

The thread pool parameters of @Async can be configured as follows:

#Number of core threads
spring.task.execution.pool.core-size=200
#Maximum number of threads
spring.task.execution.pool.max-size=1000
#Idle thread retention time
spring.task.execution.pool.keep-alive =3s
#Queue capacity
spring.task.execution.pool.queue-capacity=1000
#Thread name prefix
spring.task.execution.thread-name-prefix=test-thread-

    4. Change the @Scheduled annotated method internally to asynchronous execution

//Of course, building a reasonable thread pool is also key, otherwise the submitted task will also block the ExecutorService
    service = Executors.newFixedThreadPool(5);
 
    @Scheduled(cron = "0/1 * * * * ? ")
    public void deleteFile() {         service.execute(() -> {             log.info("111delete success, time:" + new Date().toString());             try {                 Thread.sleep(1000 * 5);//After changing to asynchronous execution, no matter how time-consuming you are, you will not be impressed by the scheduled scheduling of subsequent tasks             } catch (InterruptedException e) {                 e.printStackTrace();             }         });     }     @Scheduled(cron = "0/1 * * * * ? ")     public void syncFile() {         service.execute(()->{









 



            log.info("222sync success, time:" + new Date().toString());
        });
    }

5.Quartz

First we need to understand some basic concepts in quartz:

    Scheduler: Task scheduler is the controller that actually performs task scheduling. Encapsulated through SchedulerFactoryBean in spring.

    Trigger: Trigger, used to define time rules for task scheduling, including SimpleTrigger, CronTrigger, DateIntervalTrigger, etc. CronTrigger is used more often. This article mainly introduces this method. CronTrigger is encapsulated in CronTriggerFactoryBean in spring.

    SimpleTrigger: A simple trigger, starting from a certain time, triggering every time, and repeating how many times.

    CronTrigger: Use cron expressions to define trigger time rules, such as "0 0 0,2,4 1/1 *? *" means triggering at 0, 2, and 4 o'clock every day.

    DailyTimeIntervalTrigger: a time period every day, triggered every N time units, the time unit can be milliseconds, seconds, minutes, hours

    CalendarIntervalTrigger: Triggered every N time units. The time unit can be milliseconds, seconds, minutes, hours, days, months, and years.

    Calendar: It is a collection of specific time points in the calendar. A trigger can contain multiple Calendars to exclude or include certain time points.

    JobDetail: Used to describe the Job implementation class and other related static information, such as Job name, associated listener and other information. There are two implementations of JobDetailFactoryBean and MethodInvokingJobDetailFactoryBean in spring. If task scheduling only needs to execute a certain method of a certain class, it can be called through MethodInvokingJobDetailFactoryBean.

    Job: is an interface with only one method void execute(JobExecutionContext context). Developers implement this interface to define running tasks. The JobExecutionContext class provides various information about the scheduling context. Job runtime information is stored in the JobDataMap instance. Tasks that implement the Job interface are stateless by default. If you want to set the Job to be stateful (that is, whether it supports concurrency), add the @DisallowConcurrentExecution annotation to the implemented Job in quartz.

    The core elements of Quartz task scheduling are scheduler, trigger and job, where trigger and job are metadata of task scheduling, and scheduler is the controller that actually performs scheduling.

    In Quartz, trigger is an element used to define scheduling time, that is, according to what time rules to execute tasks. Quartz mainly provides four types of triggers: SimpleTrigger, CronTirgger, DailyTimeIntervalTrigger, and CalendarIntervalTrigger

    In Quartz, job is used to represent scheduled tasks. There are two main types of jobs: stateless and stateful. For the same trigger, stateful jobs cannot be executed in parallel. The next execution can only be triggered after the last triggered task is executed. Job mainly has two attributes: volatility and durability, where volatility indicates whether the task is persisted to the database storage, and durability indicates whether the task is retained when there is no trigger association. Both tasks are persisted or retained when the value is true. A job can be associated with multiple triggers, but a trigger can only be associated with one job.

use

    Introduce starter dependencies

  <!-- quartz -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

    Write two tasks Task

/**
 * @author
 * Task 1
 */
public class TestTask1 extends QuartzJobBean{

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("TestQuartz01----" + sdf.format(new Date()));
    }
}


/**
 * 任务二
 * @author
 */
public class TestTask2 extends QuartzJobBean{
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("TestQuartz02----" + sdf.format(new Date()));
    }
}
 

    Write configuration class

/**
 * quartz configuration class
 */
@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail testQuartz1() {
        return JobBuilder.newJob(TestTask1.class).withIdentity("testTask1").storeDurably().build();
    }

    @Bean
    public Trigger testQuartzTrigger1() {
        //5秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(5)
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(testQuartz1())
                .withIdentity("testTask1")
                .withSchedule(scheduleBuilder)
                .build();
    }

    @Bean
    public JobDetail testQuartz2() {
        return JobBuilder.newJob(TestTask2.class).withIdentity("testTask2").storeDurably().build();
    }

    @Bean
    public Trigger testQuartzTrigger2() {         //cron mode, executed every 5 seconds         return TriggerBuilder.newTrigger().forJob(testQuartz2())                 .withIdentity("testTask2")                 .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))                 .build();     }






}

    Start task observation

You can see that the task starts normally and the task Task is executed:

image-20210116214659029
6. Comparison between several frameworks
Timer and ScheduledThreadPoolExecutor

    Timer's support for scheduling is based on absolute time, so tasks are sensitive to changes in system time; ScheduledThreadPoolExecutor supports relative time.

    Timer uses a single thread to execute all TimerTasks. If a TimerTask is time-consuming, it will affect the execution of other TimerTasks; and ScheduledThreadPoolExecutor can construct a fixed-size thread pool to execute tasks.

    Timer will not catch unchecked exceptions thrown by TimerTask, so when an exception is thrown, Timer will terminate, causing the unfinished TimerTask to no longer be executed, and new TimerTask cannot be scheduled; ScheduledThreadPoolExecutor properly solves this problem The processing will not affect the execution of other tasks.
——————————————
Copyright Statement: This article is an original article by CSDN blogger “njitzyd” and follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this statement when reprinting .
Original link: https://blog.csdn.net/qq_37687594/article/details/119943278

Guess you like

Origin blog.csdn.net/qq_16504067/article/details/131555359