Spring排程定時任務的方式
spring排程定時任務的方式
spring 定時器任務scheduled-tasks預設配置是單執行緒序列執行的,多個任務相當於序列。每個job都是等待上個執行完了才執行下一個job。這就造成了若某個任務執行時間過長,其他任務一直在排隊,業務邏輯沒有及時處理的問題。
單執行緒執行定時任務帶來的問題
spring排程定時任務的方式就會導致:bTask會因為aTask的超時執行而延遲執行。
如下是scheduled定義了3個任務。
<task:scheduled-tasks >
<task:scheduled ref="myTask1" method="run" cron="0 0/59 10-23 * * ?"/>
<task:scheduled ref="myTask2" method="run" cron="0/10 * * * * ?"/>
<task:scheduled ref="myTask3" method="run" cron="0/10 * * * * ?"/>
</task:scheduled-tasks>
檢視該任務17點的執行日誌(task名字已修改)
zgrep -e '2016-10-28 17:' channel-task.log.2016-10-28.log.gz | grep -e 'MyTask2'
2016-10-28 17:14:25,002 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:14:35,980 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task MyTask2@186d315
2016-10-28 17:14:40,002 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:14:50,681 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task .MyTask2@186d315
2016-10-28 17:14:55,003 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:15:05,613 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task MyTask2@186d315
2016-10-28 17:20:35,246 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:20:46,051 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task .MyTask2@186d315
2016-10-28 17:20:50,003 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:21:00,974 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task MyTask2@186d315
MyTask2每10秒鐘執行一次,但是在17:15:05 到17:20:35之間,5分鐘內定時任務沒有執行。
執行命令 zgrep -e '2016-10-28 17:1' task.log.2016-10-28.log.gz
(當天17點10幾分發生的日誌)。然後在查詢日誌發現,這5分鐘之內有大量的日誌在執行。
2016-10-28 17:17:20,202 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280893418 ]
2016-10-28 17:17:20,477 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280893401 ]
2016-10-28 17:17:20,731 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280893402 ]
.........中間省略n條日誌
2016-10-28 17:19:59,752 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280894049 ]
通過過以上日誌可以看出,該執行緒[pool-8-thread-1 - ]
一直在處理MyTask3任務,此時斷定 task:scheduled 配置預設是單執行緒序列的。網上查詢資料發現如下配置可以解決問題:
<task:scheduler id="scheduler" pool-size="3" />
<task:scheduled-tasks scheduler="scheduler" >
<task:scheduled ref="myTask1" method="run" cron="0 0/59 11-23 * * ?"/>
<task:scheduled ref="myTask2" method="run" cron="0/10 * * * * ?"/>
<task:scheduled ref="myTask3" method="run" cron="0/10 * * * * ?"/>
</task:scheduled-tasks>
MethodInvokingJobDetailFactoryBean併發問題
Spring中可以通過配置方便的實現週期性定時任務管理,這需要用到以下幾個類:
- MethodInvokingJobDetailFactoryBean:此工廠主要用來製作一個jobDetail,即製作一個任務。由於我們所做的定時任務根本上講其實就是執行一個方法。所以用這個工廠比較方便。
- SimpleTriggerBean:定時器,負責配置啟動時間、執行週期。
- SchedulerFactoryBean:觸發器,負責配置所有定時器。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<bean id="myJob1Obj" class="com.vip.service.job.MyJob1" />
<bean id="myJob1"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myJob1Obj" />
<property name="targetMethod" value="doJob" />
<property name="concurrent" value="false" />
</bean>
<bean id="myJob1CronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="myJob1" />
<property name="cronExpression" value="0/3 * * * * ?"></property>
</bean>
<bean id="myJob2Obj" class="com.vip.service.job.MyJob2" />
<bean id="myJob2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myJob2Obj" />
<property name="targetMethod" value="doJob" />
<property name="concurrent" value="false" />
</bean>
<bean id="myJob2CronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="myJob2" />
<property name="cronExpression" value="0/5 * * * * ?"></property>
</bean>
<bean id="myJob3Obj" class="com.vip.service.job.MyJob3" />
<bean id="myJob3"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myJob3Obj" />
<property name="targetMethod" value="doJob" />
<property name="concurrent" value="false" />
</bean>
<bean id="myJob3CronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="myJob3" />
<property name="cronExpression" value="0/5 * * * * ?"></property>
</bean>
<bean id="jobQuertz"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
lazy-init="false">
<property name="applicationContextSchedulerContextKey" value="applicationContext" />
<property name="jobDetails">
<list>
<ref bean="myJob3" />
<ref bean="myJob1" />
<ref bean="myJob2" />
</list>
</property>
<property name="schedulerName" value="AdsScheduler" />
<property name="triggers">
<list>
<ref bean="myJob3CronTrigger" />
<ref bean="myJob2CronTrigger" />
<ref bean="myJob1CronTrigger" />
</list>
</property>
<property name="startupDelay" value="15" />
<property name="overwriteExistingJobs" value="true" />
<property name="autoStartup" value="true" />
</bean>
</beans>
concurrent:對於相同的JobDetail,當指定多個Trigger時, 很可能第一個job完成之前,第二個job就開始了。定concurrent設為false,多個job不會併發執行,第二個job將不會在第一個job完成之前開始。
MethodInvokingJobDetailFactoryBean類預設是併發執行的,這時候如果不設定“concurrent”為false,很可能帶來併發或者死鎖的問題,而且機率較小,不容易復現,請大家使用的時候注意設定“concurrent”。
相關文章
- Linux 定時任務排程Linux
- Android 中的定時任務排程Android
- laravel框架任務排程(定時執行任務)Laravel框架
- Spring 指南(排程任務)Spring
- 使用Java實現定時任務排程Java
- 基於Azkaban的任務定時排程實踐
- Spring Boot 實現定時任務的 4 種方式Spring Boot
- 用海豚排程器定時排程從Kafka到HDFS的kettle任務指令碼Kafka指令碼
- DolphinScheduler心臟:Quartz的定時任務排程框架深度解析quartz框架
- Spring Boot 中實現定時任務的兩種方式Spring Boot
- 深入 Java Timer 定時任務排程器實現原理Java
- 任務排程
- 『學了就忘』Linux系統定時任務 — 89、任務排程工具anacronLinux
- Spring - Task定時任務Spring
- spring boot中的定時任務Spring Boot
- Airflow 任務排程AI
- Laravel 任務排程Laravel
- spring定時任務註解Spring
- Spring Boot應用中進行任務排程Spring Boot
- [原始碼分析] 定時任務排程框架 Quartz 之 故障切換原始碼框架quartz
- 聊聊PowerJob的任務排程
- dcat-admin版的定時任務管理排程擴充套件釋出套件
- 一個輕量級的分散式定時任務排程平臺-Cloudtask分散式Cloud
- 十七、.net core(.NET 6)搭建基於Quartz元件的定時排程任務quartz元件
- 3分鐘帶你掌握Spring Boot中的定時排程服務Spring Boot
- Spring Boot 配置 Quartz 定時任務Spring Bootquartz
- 分散式任務排程分散式
- 使用RestCloud ETL Shell元件實現定時排程DataX離線任務RESTCloud元件
- Spring Task定時任務的配置和使用Spring
- Spark中資源排程和任務排程Spark
- Spring Boot2 系列教程(十六)定時任務的兩種實現方式Spring Boot
- 封裝定時任務框架的正確方式封裝框架
- Python實現定時任務的多種方式Python
- Spring定時任務高階使用篇Spring
- Spring之定時任務基本使用篇Spring
- Spring Boot Quartz 分散式叢集任務排程實現Spring Bootquartz分散式
- Timer和TimerTask 任務排程
- 分散式排程任務-ElasticJob分散式AST