背景
今天debug項目時發現所有定時任務在程序啓動時執行幾次後就不執行了
檢查代碼也沒發現有什麼問題 通過jstack查看線程信息時 發現只有一個名字爲scheduling-1的線程 而且還是time-waiting狀態的 分析調用鏈發現是手動調用了Thread.sleap方法導致
原因: 項目中有多個定時任務要運行 而只有一個核心線程 還是阻塞的 所以其他定時任務得不到執行
分析方案
jstack 25097|grep scheduling -A 10
查看結果請點擊附錄1
解決方案
爲定時任務配置線程池 讓它支持多線程
asyncTaskExecutor 針對@Async方法
taskScheduler 針對@Scheduled方法
public class TaskConfig {
public TaskConfig() {
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnAnnotation(EnableAsync.class)
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(12);
executor.setQueueCapacity(20);
executor.setMaxPoolSize(50);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("async-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.setRejectedExecutionHandler(RejectedExecutionHandlers.discardPolicy());
return executor;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnAnnotation(EnableScheduling.class)
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(8);
scheduler.setThreadNamePrefix("task-");
scheduler.setWaitForTasksToCompleteOnShutdown(true);
scheduler.setAwaitTerminationSeconds(60);
return scheduler;
}
}
@Import({TaskConfig.class})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableTaskMultiThreading {
}
@EnableTaskMultiThreading 開啓任務多線程支持
@SpringBootApplication
@EnableScheduling
@EnableTaskMultiThreading
public class Application {
public static void main(String[] args) {
SpringApplication.run(XynetServiceStatisticsApplication.class, args);
}
}
附錄1
nailsoul@nailsoul-company-pc:~$ jstack 25097|grep scheduling -A 10
"scheduling-1" #81 prio=5 os_prio=0 tid=0x00007fd556891000 nid=0x629a waiting on condition [0x00007fd52d69f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.xynet.cloud.core.util.ThreadUtil.sleep(ThreadUtil.java:6)
at com.xynet.statistics.service.impl.StatisticsLeakyScreenScanningServiceImpl.scannerStatisticsLeakyScreenDatasByType(StatisticsLeakyScreenScanningServiceImpl.java:184)
at com.xynet.statistics.service.impl.StatisticsLeakyScreenScanningServiceImpl.scannerStatisticsLeakyScreenTaskByCrontab(StatisticsLeakyScreenScanningServiceImpl.java:123)
at com.xynet.statistics.service.impl.StatisticsLeakyScreenScanningServiceImpl.scannerStatisticsLeakyScreenDatas(StatisticsLeakyScreenScanningServiceImpl.java:79)
at com.xynet.statistics.config.StatisticsSchedule.startRecordLeakyScreenScanner(StatisticsSchedule.java:123)
at com.xynet.statistics.config.StatisticsSchedule$$FastClassBySpringCGLIB$$e54fcc5a.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
--
at org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAspect.traceBackgroundThread(TraceSchedulingAspect.java:73)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
--
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.cloud.sleuth.instrument.async.TraceRunnable.run(TraceRunnable.java:67)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
nailsoul@nailsoul-company-pc:~$