Spring Boot timed task single-threaded and multi-threaded @Scheduled

Timing tasks for Spring Boot:

The first one: configure the parameters into the .properties file:

code:

package com.accord.task;
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
/**
 * 从配置文件加载任务信息
 */
@Component
public class ScheduledTask {
    
    
 
  private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
 
  //@Scheduled(fixedDelayString = "${jobs.fixedDelay}")
  @Scheduled(fixedDelayString = "2000")
  public void getTask1() {
    
    
    System.out.println("任务1,从配置文件加载任务信息,当前时间:" + dateFormat.format(new Date()));
  }
 
  @Scheduled(cron = "${jobs.cron}")
  public void getTask2() {
    
    
    System.out.println("任务2,从配置文件加载任务信息,当前时间:" + dateFormat.format(new Date()));
  }
}

application.properties file:

jobs.fixedDelay=5000
jobs.cron=0/5 * *  * * ?

In SpringBootCron2Application.java:

package com.accord;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
 
@SpringBootApplication
@EnableScheduling
public class SpringBootCron2Application {
    
    
	public static void main(String[] args) {
    
    
		SpringApplication.run(SpringBootCron2Application.class, args);
	}
}

Note: @EnableScheduling must be added; otherwise, the task will not be started regularly!

Parameter description in @Scheduled:

@Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行;
 
@Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行;
 
@Scheduled(initialDelay=1000, fixedDelay=2000):第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行;
 
@Scheduled(cron="* * * * * ?"):按cron规则执行。

Online Cron expression generator: http://cron.qqe2.com/

The second timing task: single-threaded and multi-threaded

1. Create a scheduled task:

package com.accord.task;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
/**
 * 构建执行定时任务
 */
@Component
public class ScheduledTask2 {
    
    
 
    private Logger logger = LoggerFactory.getLogger(ScheduledTask2.class);
 
    private int fixedDelayCount = 1;
    private int fixedRateCount = 1;
    private int initialDelayCount = 1;
    private int cronCount = 1;
 
    @Scheduled(fixedDelay = 5000)        //fixedDelay = 5000表示当前方法执行完毕5000ms后,Spring scheduling会再次调用该方法
    public void testFixDelay() {
    
    
        logger.info("===fixedDelay: 第{}次执行方法", fixedDelayCount++);
    }
 
    @Scheduled(fixedRate = 5000)        //fixedRate = 5000表示当前方法开始执行5000ms后,Spring scheduling会再次调用该方法
    public void testFixedRate() {
    
    
        logger.info("===fixedRate: 第{}次执行方法", fixedRateCount++);
    }
 
    @Scheduled(initialDelay = 1000, fixedRate = 5000)   //initialDelay = 1000表示延迟1000ms执行第一次任务
    public void testInitialDelay() {
    
    
        logger.info("===initialDelay: 第{}次执行方法", initialDelayCount++);
    }
 
    @Scheduled(cron = "0 0/1 * * * ?")  //cron接受cron表达式,根据cron表达式确定定时规则
    public void testCron() {
    
    
        logger.info("===initialDelay: 第{}次执行方法", cronCount++);
    }
 
}

Use @Scheduled to create a scheduled task This annotation is used to mark a scheduled task method.
By looking at the @Scheduled source code, we can see that it supports a variety of parameters:
(1) cron: cron expression, specifying the task to be executed at a specific time;
(2) fixedDelay: Indicates how long after the last task execution is completed, the parameter type is long , the unit is ms;
(3) fixedDelayString: same meaning as fixedDelay, but the parameter type is changed to String;
(4) fixedRate: indicates that the task is executed at a certain frequency, the parameter type is long, and the unit is ms;
(5) fixedRateString: same as fixedRate The meaning is the same, just change the parameter type to String;
(6) initialDelay: Indicates how long to delay before executing the task for the first time, the parameter type is long, and the unit is ms;
(7) initialDelayString: The meaning is the same as initialDelay, just change the parameter type to It is String;
(8) zone: time zone, the default is the current time zone, which is generally not used.

2. Start the scheduled task:

package com.accord;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
 
@SpringBootApplication
@EnableScheduling
public class SpringBootCron2Application {
    
    
	public static void main(String[] args) {
    
    
		SpringApplication.run(SpringBootCron2Application.class, args);
	}
}

Note: The @EnableScheduling annotation here is used to discover the tasks annotated @Scheduled and execute them in the background. Without it, scheduled tasks cannot be executed.
Quoting the original official document:
@EnableScheduling ensures that a background task executor is created. Without it, nothing gets scheduled.

3. Execution result (single thread)

A simple timed task model is completed. Next, execute springBoot to observe the execution results:

img

From the results entered in the console, we can see that all scheduled tasks are processed by the same thread in the same thread pool, so how do we process each scheduled task concurrently? Please continue to look down.

4. Multi-threaded processing of timing tasks:

Seeing the results of the console output, all scheduled tasks are processed through a thread. I guess a SingleThreadScheduledExecutor is set in the configuration of the scheduled tasks, so I looked at the source code and searched all the way from the ScheduledAnnotationBeanPostProcessor class. Sure enough, there is another judgment in ScheduleTasks in ScheduledTaskRegistrar (timed task registration class):

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

This means that if the taskScheduler is empty, then a single-threaded thread pool is created for the timed task, and there is also a method for setting the 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());
	}
}

In this way, the problem is very simple. We only need to explicitly set a ScheduledExecutorService by calling this method to achieve the concurrency effect. All we have to do is to implement the SchedulingConfigurer interface and rewrite the configureTasks method;

package com.accord.task;
 
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
 
import java.util.concurrent.Executors;
 
/**
 * 多线程执行定时任务
 */
@Configuration
//所有的定时任务都放在一个线程池中,定时任务启动时使用不同都线程。
public class ScheduleConfig implements SchedulingConfigurer {
    
    
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    
    
        //设定一个长度10的定时任务线程池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    }
}

5. Execution result (concurrency)

img

From the results output by the console, it can be seen that each scheduled task is processed by a different thread.

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/131345161
Recommended