你的位置:首页 > 软件开发 > Java > Spring @Scheduled @Async联合实现调度任务(2017.11.28更新)

Spring @Scheduled @Async联合实现调度任务(2017.11.28更新)

发布时间:2017-11-29 06:00:11
定时任务之前一直用的是quartz之类,但是注意到Spring中其实也提供了一种简单的调度注释@Scheduled,也就想尝一下鲜..代码示意如下:@Component@EnableSchedulingpublic class AsyncTaskHandlerTask { @Sc ...

定时任务之前一直用的是quartz之类,但是注意到Spring中其实也提供了一种简单的调度注释@Scheduled,也就想尝一下鲜..

代码示意如下:

@Component@EnableSchedulingpublic class AsyncTaskHandlerTask { @Scheduled(fixedDelay = 1000) public void task1() {   //输出日志 } @Scheduled(fixedDelay = 1000) public void task2() {   //输出日志  }}

执行了一下,完全ok,日志打印正常,2个任务也都正常定时执行了.那好,添加些业务逻辑进去:

@Component@EnableSchedulingpublic class AsyncTaskHandlerTask { @Scheduled(fixedDelay = 1000) public void task1() {   while(true){   ....   } } @Scheduled(fixedDelay = 1000) public void task2() {   while(true){   ....   }  }}

再启动,咦,奇怪了,怎么定时任务没有执行呢?倘使我之前没有输出日志试验,我可能就认为注解的用法错了呢...重新添加日志,下断点重跟了一下启动过程发现:

程序进入到while死循环后就卡死了,没有再继续启动另一个定时任务了.通过现象可知@Scheduled启动过程是一个单线程同步启动过程,故一旦中途被阻塞,会导致整个启动过程阻塞,

其余的定时任务都不会启动.这明显很奇怪,网上的教程大多数是

务.但是Javaconfig形式的则没有说明.但是我查询到了另一个注解@Async,这个异步注解我是使用过的,可以指定线程池,打到方法上后便会以指定的线程池来执行方法.然后解决方案来了:

@Component@EnableSchedulingpublic class AsyncTaskHandlerTask { @Scheduled(fixedDelay = 1000) @Async public void task1() {   while(true){   ....   } } @Scheduled(fixedDelay = 1000) @Async public void task2() {   while(true){   ....   }  }}

再次启动,不会再被阻塞.

2017-11-28更新:

本来以为找到了正解,结果证明是误入了歧途..以上是完全错误的使用,虽然看起来貌似是正确的..正应了一句话啊,啥都不如看源码啊...

太懒了,本来这个应该再单独开个文章再说的,但是太懒了...

进入正题,按照如上实现部署后突然发现一个诡异的问题,定时任务发生了异常的"阻塞"现象,某个任务突然看起来不再执行了,直接卡死了.第一印象是死锁了,直接jstack生成了一份堆栈信息,仔细分析后发现一个诡异问题,定时任务并没有像Scheduled定义的那样一次结束后再执行下一次,而是并发执行多次,直接将Async定义的线程池跑满.那么问题也就好解释了,Async注解后,直接异步在新线程中执行任务,由于异步执行Scheduled认为上一次已经执行完马上开始执行下一次,导致不停执行定时任务直接跑满Async使用的线程池.那么这实际上是一种错误的使用方法..怎么办?

只好点了@EnableScheduling注解看一下源码中怎么说的吧.

 

* <p>When more control is desired, a {@code @Configuration} class may implement * {@link SchedulingConfigurer}. This allows access to the underlying * {@link ScheduledTaskRegistrar} instance. For example, the following example * demonstrates how to customize the {@link Executor} used to execute scheduled * tasks:

 

实际上已经说的很明白了,更多的控制,只需要继承 SchedulingConfigurer 这个类,之前没有找到对应

 * public class AppConfig implements SchedulingConfigurer { * *  @Override *  public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { *   taskRegistrar.setScheduler(taskExecutor()); *  } * *  @Bean(destroyMethod="shutdown") *  public Executor taskExecutor() { *   return Executors.newScheduledThreadPool(100); *  } * }

标红处就是使用线程池的配置,之后再执行不仅以多线程来启动定时任务,而且也不会出现定时任务重复并发执行的问题.至此此问题圆满解决.再感叹下啥都不如看源码.

 

 

海外公司注册、海外银行开户、跨境平台代入驻、VAT、EPR等知识和在线办理:https://www.xlkjsw.com

原标题:Spring @Scheduled @Async联合实现调度任务(2017.11.28更新)

关键词:Spring

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

可能感兴趣文章

我的浏览记录