Spring Task 使用
Contents
使用
<bean id="updateRsstask" class="xxxx.xxx.xx" />
<task:executor id="myexecutor" pool-size="10" />
<task:scheduler id="myscheduler" pool-size="10" />
<task:scheduled-tasks scheduler="myscheduler">
<!-- 每隔一个小时更新rss -->
<task:scheduled ref="updateRssTask" method="execute" cron="0 0 * * * *" />
</task:scheduled-tasks>
注意事项
<task:schedule-tasks scheduler="myscheduler">
这里的scheduler
必须显式指定,否则它只会使用默认的值,默认为单线程的。
<task:scheduler id="scheduler" pool-size="10"/>
如果在xml里这样子配置scheduler
,则使用的是ThreadPoolTaskScheduler
.
<task:executor id="executor" pool-size="10"/>
如果在xml里这样子配置executor
,则使用的是ThreadPoolTaskExecutor
excutor属性说明
<task:executor
id="executorWithCallerRunsPolicy"
pool-size="5-25"
queue-capacity="100"
rejection-policy="CALLER_RUNS"/>
pool-size
:线程池大小,如果只是设置了一个值。则corePoolsize和maxPoolSize
都是这个值。
queue-capacity
:队列大小
rejection-policy
: 队列满的时候,使用的拒绝策略。
拒绝策略有:
ABORT(缺省)
:抛出TaskRejectedException异常,然后不执行
DISCARD
:不执行,也不抛出异常
DISCARD_OLDEST
:丢弃queue中最旧的那个任务
CALLER_RUNS
:不在新线程中执行任务,而是有调用者所在的线程来执行
这些属性的默认值,可以到org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
类看.如下:
private int corePoolSize = 1;
private int maxPoolSize = Integer.MAX_VALUE;
private int keepAliveSeconds = 60;
private boolean allowCoreThreadTimeOut = false;
private int queueCapacity = Integer.MAX_VALUE;
task异常处理器使用
<bean id="scheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
<property name="poolSize" value="5" />
<property name="errorHandler" ref="scheduledTaskErrorHandler" />
</bean>
<bean id="scheduledTaskErrorHandler" class="boo.ScheduledTaskErrorHandler" />
public class ScheduledTaskErrorHandler implements ErrorHandler {
@Override
public void handleError(Throwable t) {
// do something, like shutdown the scheduler
}
}
executor vs scheduler
默认情况下,类似:
<task:scheduled-tasks scheduler="myScheduler">
<task:scheduled ref="taskDemo" method="run" cron="*/5 * * * * *" />
<task:scheduled ref="taskDemo2" method="run" cron="*/5 * * * * *" />
</task:scheduled-tasks>
这些任务,既是 myScheduler 调度并执行 的。那么,我们的 myexecutor 定义了有什么用呢?如果我们只是想 myScheduler 只是调度,而让 executor 来执行我们的任务,则可以这样子配置:
在方法上加上注解 @Async
@Async
public void run() throws InterruptedException {
log.info("this is a task");
Thread.sleep(8*1000);
log.info("this is a task end");
}
然后要xml里配置时要加上:
<task:annotation-driven executor="myExecutor" scheduler="myScheduler" />
这样子,task 的方法,就会由 myExecutor 线程池来执行了。
如果 task 任务数比 myscheduler 多,并且没有 @Async 和 executor
因为这些 task 都是要由 myScheduler 调度并执行的,如果 myScheduler 线程池数量不足够,则可能会导致有些任务,并没有在我们预期的时间点中执行!这个要特别注意。
比如,myScheduler 的线程池数是1,但有2个 task,要在同一时间点执行(模拟 myScheduler 数不足的情况),这时,虽然调度时,是调度了两个,但实际执行时,是一个一个地执行的。
假设每个方法执行都要3秒,而我们的定时任务是每5秒种执行一次(如果我们的 task 依赖于特点时间点的话),那第二个task真正的执行时间点是第8秒(5+3)才会执行的。