当前位置:   article > 正文

springtask 任务执行暂停问题_停止spring定时任务报了中段异常

停止spring定时任务报了中段异常

项目场景:

SpringBoot项目,多个定时任务执行,注解为@Scheduled(七子表达式)


问题描述:

项目启动,正常执行一段时间,其中一个定时任务停止运行,查看日志报错信息出现Scheduled字样,确定是定时任务出错


原因分析:

1.由于SpringBoot执行多个定时任务为单线程执行,即执行完A任务才执行B任务,则当A任务与B任务的周期时间不一致,且其中一个任务阻塞时,另一个任务会同步阻塞

2.项目中其中一个定时任务为http请求,且在定时任务停止运行前,该http请求有报错。怀疑http请求过程中出现某种错误导致http请求僵死,致使线程不再往下执行,最终导致后续的定时任务也不再执行


简单实验:

  1. @Component
  2. public class Test {
  3. private static final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
  4. private int count = 1;
  5. @Scheduled(cron = "0/3 * * * * ?")
  6. public void first(){
  7. System.out.println("A:现在时间:" + format.format(new Date()) + "---" + Thread.currentThread().getName());
  8. }
  9. @Scheduled(cron = "0/5 * * * * ?")
  10. public void second(){
  11. if(count == 5){
  12. try {
  13. Thread.sleep(15000);
  14. } catch (InterruptedException e) {
  15. throw new RuntimeException(e);
  16. }
  17. throw new RuntimeException();
  18. }
  19. System.out.println("B:现在时间:" + format.format(new Date()) + "---" + Thread.currentThread().getName());
  20. count++;
  21. }
  22. }
  1. A:现在时间:15:04:09---scheduling-1
  2. B:现在时间:15:04:10---scheduling-1
  3. A:现在时间:15:04:12---scheduling-1
  4. A:现在时间:15:04:15---scheduling-1
  5. B:现在时间:15:04:15---scheduling-1
  6. A:现在时间:15:04:18---scheduling-1
  7. B:现在时间:15:04:20---scheduling-1
  8. A:现在时间:15:04:21---scheduling-1
  9. A:现在时间:15:04:24---scheduling-1
  10. java.lang.RuntimeException: null
  11. at com.fl.video.stat.test.Test.second(Test.java:35) ~[classes/:na]
  12. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_161]
  13. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_161]
  14. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161]
  15. at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161]
  16. at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  17. at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  18. at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93) [spring-context-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  19. at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_161]
  20. at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_161]
  21. at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_161]
  22. at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_161]
  23. at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_161]
  24. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_161]
  25. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_161]
  26. at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161]
  27. A:现在时间:15:04:40---scheduling-1
  28. A:现在时间:15:04:42---scheduling-1

由上述代码及日志可知:

B应该在15:04:25再次执行,A应该在15:04:27再次执行,但由于代码中的sleep以及报错,导致B被阻塞了,此时A也被阻塞了,也就印证了猜测的第一条。但在15秒以后即15:04:40,A再次恢复了运行,并没有因为B的报错而导致A的停止运行


解决方案:

针对于第一条猜测:

        单个线程定时任务防止阻塞

                1.启动类加入注解支持@EnableAsync
                2.在定时任务方法上加入注解@Async

        这里其实就是通过增加注解来使SpringBoot单线程定时任务变成了多线程

        还有另外一种方法为自己定义线程池,同样可以解决这个问题

  1. @Component
  2. public class Test {
  3. private static final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
  4. private int count = 1;
  5. @Scheduled(cron = "0/3 * * * * ?")
  6. @Async
  7. public void first(){
  8. System.out.println("A:现在时间:" + format.format(new Date()) + "---" + Thread.currentThread().getName());
  9. }
  10. @Scheduled(cron = "0/5 * * * * ?")
  11. @Async
  12. public void second(){
  13. if(count == 5){
  14. try {
  15. Thread.sleep(15000);
  16. } catch (InterruptedException e) {
  17. throw new RuntimeException(e);
  18. }
  19. throw new RuntimeException();
  20. }
  21. System.out.println("B:现在时间:" + format.format(new Date()) + "---" + Thread.currentThread().getName());
  22. count++;
  23. }
  24. }
  1. A:现在时间:15:24:04---task-1
  2. B:现在时间:15:24:05---task-3
  3. A:现在时间:15:24:06---task-4
  4. A:现在时间:15:24:09---task-5
  5. B:现在时间:15:24:10---task-6
  6. A:现在时间:15:24:12---task-7
  7. A:现在时间:15:24:15---task-2
  8. B:现在时间:15:24:15---task-8
  9. A:现在时间:15:24:18---task-1
  10. A:现在时间:15:24:21---task-4
  11. A:现在时间:15:24:24---task-5
  12. A:现在时间:15:24:27---task-7
  13. A:现在时间:15:24:30---task-2
  14. A:现在时间:15:24:33---task-1
  15. java.lang.RuntimeException: null
  16. at com.fl.video.stat.test.Test.second(Test.java:38) ~[classes/:na]
  17. at com.fl.video.stat.test.Test$$FastClassBySpringCGLIB$$534a3a02.invoke(<generated>) ~[classes/:na]
  18. at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  19. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  20. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  21. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  22. at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.2.8.RELEASE.jar:5.2.8.RELEASE]
  23. at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) ~[na:1.8.0_161]
  24. at java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:1.8.0_161]
  25. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_161]
  26. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_161]
  27. at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_161]
  28. A:现在时间:15:24:36---task-5

单线程阻塞问题解决,另外一种利用线程池的解决方式可以看参考博文

参考博文:springTask阻塞问题_QAQiiii的博客-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/83566
推荐阅读
相关标签
  

闽ICP备14008679号