@Scheduled(cron = "0 44 14 * * ?")
public void dataCrawlProcess(){
tldDataProcessService.processData();
}
@Scheduled(cron = "0/5 * * * * ?")
public void dataCrawlProcess2(){
log.info("18 15 任务");
}
@Scheduled(cron = "0/4 * * * * ?")
public void dataCrawlProcess3(){
log.info("17 15 任务");
try {
while (true) {
//模拟耗时任务,阻塞10s
Thread.sleep(80000);
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("17 15 任务完成");
}
@Scheduled(fixedDelay = 60000)//every 60 seconds.
public void fetchOperatorData() {
}
同一时间只有一个可以执行
三. 解决方案
网上有多种解决方案,以下列举两种
方案一:使用@Async注解实现异步任务
这种方式比较简单,在定时任务上加上@Async注解,注意:需启动类配合加上 @EnableAsync才会生效
代码如下:
@Component
@Log4j2
public class ScheduledTask {
@Async
@Scheduled(cron = "0/5 * * * * ?")
public void task1() throws InterruptedException {
log.info("I am task11111111, current thread: {}", Thread.currentThread());
while (true) {
//模拟耗时任务,阻塞10s
Thread.sleep(10000);
break;
}
}
@Async
@Scheduled(cron = "0/5 * * * * ?")
public void task2() {
log.info("I am task22222222, current thread: {}", Thread.currentThread());
}
}
运行结果:
2019-04-24 17:03:00.024 INFO 2152 --- [ task-1] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[task-1,5,main]
2019-04-24 17:03:00.024 INFO 2152 --- [ task-2] com.example.demo.task.ScheduledTask : I am task11111111, current thread: Thread[task-2,5,main]
2019-04-24 17:03:05.001 INFO 2152 --- [ task-3] com.example.demo.task.ScheduledTask : I am task11111111, current thread: Thread[task-3,5,main]
2019-04-24 17:03:05.001 INFO 2152 --- [ task-4] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[task-4,5,main]
2019-04-24 17:03:10.002 INFO 2152 --- [ task-5] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[task-5,5,main]
2019-04-24 17:03:10.003 INFO 2152 --- [ task-6] com.example.demo.task.ScheduledTask : I am task11111111, current thread: Thread[task-6,5,main]
由运行日志可见,定时每5s执行一次已生效,且每次任务使用的线程不一样,也即实现了多线程执行定时任务,不会出现任务等待现象。此方式据说默认线程池大小为100,要是任务不多的话有点大材小用了,所以我觉得第二种方式比较好。
方案二:手动设置定时任务的线程池大小
定时任务代码部分还原,不使用@Async注解,新增启动代码配置:
@Configuration
public class AppConfig implements SchedulingConfigurer {
@Bean
public Executor taskExecutor() {
//指定定时任务线程数量,可根据需求自行调节
return Executors.newScheduledThreadPool(3);
}
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(taskExecutor());
}
}
运行结果如下:
2019-04-24 17:26:15.008 INFO 2164 --- [pool-1-thread-2] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[pool-1-thread-2,5,main]
2019-04-24 17:26:15.008 INFO 2164 --- [pool-1-thread-1] com.example.demo.task.ScheduledTask : I am task11111111, current thread: Thread[pool-1-thread-1,5,main]
2019-04-24 17:26:20.002 INFO 2164 --- [pool-1-thread-2] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[pool-1-thread-2,5,main]
2019-04-24 17:26:25.001 INFO 2164 --- [pool-1-thread-2] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[pool-1-thread-2,5,main]
2019-04-24 17:26:30.001 INFO 2164 --- [pool-1-thread-1] com.example.demo.task.ScheduledTask : I am task11111111, current thread: Thread[pool-1-thread-1,5,main]
2019-04-24 17:26:30.001 INFO 2164 --- [pool-1-thread-3] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[pool-1-thread-3,5,main]
2019-04-24 17:26:35.001 INFO 2164 --- [pool-1-thread-3] com.example.demo.task.ScheduledTask : I am task22222222, current thread: Thread[pool-1-thread-3,5,main]
由结果可见,第二种方式也实现了多线程任务调度。
四. 总结
两种方式各有优缺点:
| 比较 | 方案一 | 方案二 |
|---|---|---|
| 优点 | 注解方式使用简单,代码量少 | 配置灵活,线程数可控 |
| 缺点 | 线程数不可控,可能存在资源浪费 | 需要增加编码 |
留个坑,从日志上看@Async方式针对同一任务也是异步的,也即task1每5s会执行一次,但是方式二貌似对同一个任务不会生效,task1执行的时候需等待上一次执行结束才会触发,并没有每5s执行一次。关于这个现象,下次再琢磨
本文探讨了Spring框架中定时任务的并发执行问题,提供了两种解决方案:一是使用@Async注解实现异步任务,二是手动设置定时任务的线程池大小。通过对比分析,帮助开发者选择适合的并发控制策略。
2650

被折叠的 条评论
为什么被折叠?



