Scheduled的单线程和多线程
1、概序
默认使用单线程模式
2、单线程执行定时任务
@Configuration
@EnableScheduling
public class TestScheduled {
private Logger logger = LoggerFactory.getLogger(TestScheduled.class);
private int fixedDelayCount = 1;
private int fixedRateCount = 1;
private int initialDelayCount = 1;
private int cronCount = 1;
/**
* fixedDelay = 5000表示当前方法执行完毕5000ms后,Spring scheduling会再次调用该方法
*/
@Scheduled(fixedDelay = 5000)
public void testFixedDelay() {
logger.info("===fixedDelay: 第{}次执行方法", fixedDelayCount++);
}
/**
* fixedRate = 5000表示当前方法开始执行5000ms后,Spring scheduling会再次调用该方法
*/
@Scheduled(fixedRate = 5000)
public void testFixedRate() {
logger.info("===fixedRate: 第{}次执行方法", fixedRateCount++);
}
/**
* initialDelay = 1000表示延迟1000ms执行第一次任务
*/
@Scheduled(initialDelay = 1000, fixedRate = 5000)
public void testInitialDelay() {
logger.info("===initialDelay: 第{}次执行方法", initialDelayCount++);
}
/**
* cron接受cron表达式,根据cron表达式确定定时规则
*/
@Scheduled(cron = "0 0/1 * * * ?")
public void testCron() {
logger.info("===initialDelay: 第{}次执行方法", cronCount++);
}
}
输出
2021-01-20 15:32:48.761 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第1次执行方法
2021-01-20 15:32:48.763 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第1次执行方法
2021-01-20 15:32:48.768 INFO 2520 --- [ main] com.hubz.scheduled.ScheduledApplication : Started ScheduledApplication in 3.157 seconds (JVM running for 7.537)
2021-01-20 15:32:49.761 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第1次执行方法
2021-01-20 15:32:53.763 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第2次执行方法
2021-01-20 15:32:53.765 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第2次执行方法
2021-01-20 15:32:54.763 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第2次执行方法
2021-01-20 15:32:58.762 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第3次执行方法
2021-01-20 15:32:58.765 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第3次执行方法
2021-01-20 15:32:59.762 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第3次执行方法
2021-01-20 15:33:00.001 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第1次执行方法
2021-01-20 15:33:03.763 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第4次执行方法
2021-01-20 15:33:03.766 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第4次执行方法
2021-01-20 15:33:04.761 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第4次执行方法
2021-01-20 15:33:08.762 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第5次执行方法
2021-01-20 15:33:08.766 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第5次执行方法
2021-01-20 15:33:09.763 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第5次执行方法
2021-01-20 15:33:13.763 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第6次执行方法
2021-01-20 15:33:13.768 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第6次执行方法
2021-01-20 15:33:14.762 INFO 2520 --- [ scheduling-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第6次执行方法
分析: 从结果可以看出每次运行时都是使用的同一个线程,但是任务之间的耗时并不发生干扰,轮询执行并轮询结果
3、@Scheduled参数
使用 @Scheduled来创建定时任务 这个注解用来标注一个定时任务方法。
通过看 @Scheduled源码可以看出它支持多种参数:
- cron:cron表达式,指定任务在特定时间执行;
- fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
- fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
- fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
- fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
- initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
- initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;
- zone:时区,默认为当前时区,一般没有用到。
@Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行;
@Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行;
@Scheduled(initialDelay=1000, fixedDelay=2000):第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行;
@Scheduled(cron="* * * * * ?"):按cron规则执行。
4、多线程执行定时任务
看到控制台输出的结果,所有的定时任务都是通过一个线程来处理的,我估计是在定时任务的配置中设定了一个SingleThreadScheduledExecutor,于是我看了源码,从ScheduledAnnotationBeanPostProcessor类开始一路找下去。果然,在ScheduledTaskRegistrar(定时任务注册类)中的ScheduleTasks中又这样一段判断:
if (this.taskScheduler == null) {
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
这就说明如果taskScheduler为空,那么就给定时任务做了一个单线程的线程池,正好在这个类中还有一个设置taskScheduler的方法:
public void setScheduler(@Nullable Object scheduler) {
if (scheduler == null) {
this.taskScheduler = null;
} else 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());
}
}
这样问题就很简单了,我们只需用调用这个方法显式的设置一个ScheduledExecutorService就可以达到并发的效果了。我们要做的仅仅是实现SchedulingConfigurer接口,重写configureTasks方法就OK了;
/**
* @author hubozhi
* @desc 多线程执行定时任务
* @datetime 2021/1/20 15:46
**/
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//所有的定时任务都放在一个线程池中,定时任务启动时使用不同都线程。
//设定一个长度10的定时任务线程池
taskRegistrar.setScheduler(new ScheduledThreadPoolExecutor(10));
}
}
换一种写法(更好):
@Configuration
public class ScheduleConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
//官方建议1-10
scheduler.setPoolSize(10);
return scheduler;
}
}
结果:
2021-01-20 15:49:07.278 INFO 16904 --- [pool-1-thread-3] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第1次执行方法
2021-01-20 15:49:09.276 INFO 16904 --- [pool-1-thread-2] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第1次执行方法
2021-01-20 15:49:10.278 INFO 16904 --- [pool-1-thread-4] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第2次执行方法
2021-01-20 15:49:10.278 INFO 16904 --- [pool-1-thread-1] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第2次执行方法
2021-01-20 15:49:13.278 INFO 16904 --- [pool-1-thread-3] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第3次执行方法
2021-01-20 15:49:14.276 INFO 16904 --- [pool-1-thread-2] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第3次执行方法
2021-01-20 15:49:16.278 INFO 16904 --- [pool-1-thread-5] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第4次执行方法
2021-01-20 15:49:17.276 INFO 16904 --- [pool-1-thread-7] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第2次执行方法
2021-01-20 15:49:18.276 INFO 16904 --- [pool-1-thread-6] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第4次执行方法
2021-01-20 15:49:19.278 INFO 16904 --- [pool-1-thread-4] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第5次执行方法
2021-01-20 15:49:22.278 INFO 16904 --- [pool-1-thread-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第5次执行方法
2021-01-20 15:49:22.278 INFO 16904 --- [pool-1-thread-8] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第6次执行方法
2021-01-20 15:49:25.278 INFO 16904 --- [pool-1-thread-8] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第7次执行方法
2021-01-20 15:49:25.279 INFO 16904 --- [pool-1-thread-9] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第3次执行方法
2021-01-20 15:49:26.277 INFO 16904 --- [pool-1-thread-1] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第6次执行方法
2021-01-20 15:49:28.277 INFO 16904 --- [pool-1-thread-5] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第8次执行方法
2021-01-20 15:49:30.276 INFO 16904 --- [pool-1-thread-7] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第7次执行方法
2021-01-20 15:49:31.278 INFO 16904 --- [pool-1-thread-4] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第9次执行方法
2021-01-20 15:49:33.281 INFO 16904 --- [pool-1-thread-6] com.hubz.scheduled.task.TestScheduled : ===fixedDelay: 第4次执行方法
2021-01-20 15:49:34.277 INFO 16904 --- [pool-1-thread-3] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第8次执行方法
2021-01-20 15:49:34.277 INFO 16904 --- [ool-1-thread-10] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第10次执行方法
2021-01-20 15:49:37.276 INFO 16904 --- [ool-1-thread-10] com.hubz.scheduled.task.TestScheduled : ===initialDelay: 第11次执行方法
2021-01-20 15:49:38.277 INFO 16904 --- [pool-1-thread-3] com.hubz.scheduled.task.TestScheduled : ===fixedRate: 第9次执行方法
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果