使用

    <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)才会执行的。