一. 介绍
Spring框架分别提供了TaskExecutor和TaskScheduler接口的异步执行和任务调度的抽象。 Spring还具有支持线程池或在应用程序服务器环境中授予CommonJ的接口的实现。 最终在公共接口背后使用这些实现可以消除Java SE 5,Java SE 6和Java EE环境之间的差异。
自JDK1.3,Spring还提供了集成类,用于支持计时器以及Quartz Scheduler([http://quartz-scheduler.org][http_quartz-scheduler.org])。这两个调度程序都使用FactoryBean进行设置,并分别具有对Timer或Trigger实例的引用。 此外,可以使用Quartz Scheduler和Timer的便利类,可以调用现有目标对象的方法(类似于普通MethodInvokingFactoryBean操作)。
二. Spring TaskExecutor
Spring 2.0引入了一个新的处理执行器的抽象。Executor是线程池概念的Java 5名称。 “executor”实际上是一个池,它的命名是由于不能保证底层实现。executor可能是单线程甚至是同步的。 Spring的抽象隐藏了Java SE 1.4,Java SE 5和Java EE环境之间的实现细节。
Spring的TaskExecutor接口与java.util.concurrent.Executor接口相同。实际上,存在的主要原因是在使用线程池时抽象出Java 5的需要。该接口具有单个方法execute(Runnable任务),该方法基于线程池的语义和配置接受执行任务。
TaskExecutor最初被创建为给其他Spring组件一个需要的线程池的抽象。诸如ApplicationEventMulticaster,JMS的AbstractMessageListenerContainer和Quartz集成的组件都使用TaskExecutor抽象来汇总线程。但是,如果您的bean需要线程池操作,则可以根据自己的需要使用此抽象。
【类型】
Spring包含了许多TaskExecutor的预构建实现。 在很大程度上,你都不需要自己去实现。
1) SimpleAsyncTaskExecutor此实现不会重用任何线程,而是启动每个调用的新线程。但是,它确实支持一个并发限制,它将阻止任何超出限制的调用,直到插槽已被释放。
2) SyncTaskExecutor此实现不会异步执行调用。相反,每个调用都发生在调用线程中。它主要用于不需要多线程的情况,如简单的测试用例。
3) ConcurrentTaskExecutor此实现是java.util.concurrent.Executor对象的适配器。还有一种替代方法,ThreadPoolTaskExecutor将Executor配置参数公开为bean属性。很少需要使用ConcurrentTaskExecutor,但是如果ThreadPoolTaskExecutor对于您的需要不够灵活,ConcurrentTaskExecutor是一种替代方案。
4) SimpleThreadPoolTaskExecutor此实现实际上是Quartz的SimpleThreadPool的子类,它可以侦听Spring的生命周期回调。当您有一个可能需要由Quartz和非Quartz组件共享的线程池时,通常使用这种方法。
5) ThreadPoolTaskExecutor这个实现是最常用的。它暴露了用于配置java.util.concurrent.ThreadPoolExecutor的bean属性,并将其包装在TaskExecutor中。
三. Spring TaskScheduler
除了TaskExecutor抽象之外,Spring 3.0引入了一个具有多种方法的TaskScheduler,以便将来在某个时间点运行任务。
public interface TaskScheduler {
ScheduledFuture schedule(Runnable task, Trigger trigger);
ScheduledFuture schedule(Runnable task, Date startTime);
ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);
ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
}
最简单的方法是一个名为“schedule”的方法,它只能运行Runnable和Date。 这将导致任务在指定时间后运行一次。 所有其他方法都能够调度任务以重复运行。 固定速率和固定延迟方法是简单的,定期执行的,但接受触发器的方法更加灵活。
【触发器接口】
触发器接口基本上受JSR-236的启发,JSR-236从Spring 3.0开始尚未正式实施。 触发器的基本思想是执行时间可以基于过去的执行结果甚至任意条件来确定。 如果这些确定确实考虑了上一次执行的结果,该信息在TriggerContext中可用。
public interface Trigger {
Date nextExecutionTime(TriggerContext triggerContext);
}
可以看到,TriggerContext是最重要的部分。 它封装了所有相关数据,如有需要,将来可以扩展。 TriggerContext是一个接口(默认情况下使用SimpleTriggerContext实现)。 在这里,您可以看到有哪些方法可用于Trigger实现。
public interface TriggerContext {
Date lastScheduledExecutionTime();
Date lastActualExecutionTime();
Date lastCompletionTime();
}
【触发器实现】
Spring提供了Trigger接口的两个实现。 最有趣的是CronTrigger。 它支持基于cron表达式的任务调度。
另一个开箱即用的实现是一个PeriodicTrigger,它接受一个固定的周期,一个可选的初始延迟值和一个布尔值,以指示该周期应该被解释为固定速率还是固定延迟。 由于TaskScheduler接口已经定义了以固定速率或固定延迟调度任务的方法,所以尽可能直接使用这些方法。 PeriodicTrigger实现的价值在于它可以在依赖于Trigger抽象的组件中使用。 例如,允许周期性触发器,基于cron的触发器,甚至自定义触发器实现可以互换使用可能是方便的。 这样的组件可以利用依赖注入的优点,使得这样的触发器可以在外部配置,因此容易地被修改或扩展。
【任务调度实现】
与Spring的TaskExecutor抽象一样,TaskScheduler的主要优点是依赖于调度行为的代码不需要耦合到特定的调度器实现。 当应用程序本身不能直接创建线程的应用程序服务器环境中运行时,它提供的灵活性尤为重要。 对于这种情况,Spring提供了一个TimerManagerTaskScheduler,它将委托给通常使用JNDI查找配置的CommonJ TimerManager实例。
一个更简单的选择,ThreadPoolTaskScheduler,可以在外部线程管理不是必需的时候使用。 在内部,它委派给ScheduledExecutorService实例。 ThreadPoolTaskScheduler实际上也实现了Spring的TaskExecutor接口,所以一个单一的实例可以尽快地用于异步执行,也可以被安排和可能的循环执行。
还没有评论,来说两句吧...