一、概述

Spring框架分别使用TaskExecutor和TaskScheduler接口提供异步执行和任务调度的抽象。Spring还提供了这些接口的实现,这些接口支持线程池或将其委托给应用服务器环境中的CommonJ。

二、TaskExecutor

Spring 2.0 开始引入的新的抽像。Executors 是线程池的Java 5名称。之所以称作是“执行器”是因为不能保证底层实现实际上是一个池;执行程序可以是单线程的,甚至是同步的。Spring的TaskExecutor接口与java.util.concurrent是等价的。

2.1 TaskExecutor类型

SimpleAsyncTaskExecutor

线程不会重用,每次调用开启一个新的线程。支持并发,超过最大并发调用数时,会阻塞,直到释放一个槽为止。

SyncTaskExecutor

不会异步执行调用。每次调用都发生在调用线程中。它主要用于不需要多线程的情况。

ConcurrentTaskExecutor

Java 5 Java .util.concurrent. executor的包装。替代方案是ThreadPoolTaskExecutor,它将Executor配置参数作为bean属性公开。很少使用。

SimpleThreadPoolTaskExecutor

Quartz的SimpleThreadPool的一个子类,它监听Spring的生命周期回调。Quartz组件和非Quartz组件共享需要共享一个线程池时,通常会使用这种方法。

ThreadPoolTaskExecutor

只能在java5中使用。公开了用于配置java.util.concurrent的bean属性。如果需要高级的东西,比如ScheduledThreadPoolExecutor,建议使用ConcurrentTaskExecutor替代。

TimerTaskExecutor

通过TimerTask支撑实现。 不同于SyncTaskExecutor,因为方法调用在一个单独的线程中执行,尽管它们在那个线程中是同步的。

WorkManagerTaskExecutor

使用CommonJ WorkManager作为它的支持实现,并且是在Spring上下文中设置CommonJ WorkManager引用的中心便利类。与SimpleThreadPoolTaskExecutor类似,这个类实现了WorkManager接口,因此也可以直接作为WorkManager使用。

2.2 使用 TaskExecutor

public class TaskExecutorExample {

private class MessagePrinterTask implements Runnable {

private String message;

public MessagePrinterTask(String message) {

this.message = message;

}

public void run() {

System.out.println(message);

}

}

private TaskExecutor taskExecutor;

public TaskExecutorExample(TaskExecutor taskExecutor) {

this.taskExecutor = taskExecutor;

}

public void printMessages() {

for (int i = 0; i < 25; i++) {

taskExecutor.execute(new MessagePrinterTask("Message" + i));

}

}

}

与其从池中检索线程并自己执行,不如将Runnable添加到队列中,而TaskExecutor使用其内部规则来决定任务何时执行

配置TaskExecutor将使用的规则

三、TaskScheduler

除了任务执行者抽象之外。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”的方法,它只接受可运行的日期。这将导致任务在指定时间后运行一次。

所有其他方法都能够安排任务重复运行。固定速率和固定延迟方法用于简单的、周期性的执行,但是使用 Trigger 的方法要灵活得多。

3.1 Trigger

触发器的基本思想是,执行时间可以根据过去的执行结果甚至任意条件来确定。如果这些决定确实考虑了前面执行的结果,那么该信息在TriggerContext中是可用的。

public interface Trigger {

Date nextExecutionTime(TriggerContext triggerContext);

}

public interface TriggerContext {

Date lastScheduledExecutionTime();

Date lastActualExecutionTime();

Date lastCompletionTime();

}

TriggerContext是最重要的部分。它封装了所有相关的数据,如果有必要,将来还可以进行扩展。TriggerContext是一个接口(默认情况下使用SimpleTriggerContext实现)。

3.2 Trigger 实现

Spring提供了触发器接口的两个实现。最有趣的是CronTrigger。它支持基于cron表达式的任务调度。

scheduler.schedule(task, new CronTrigger(" 15 9-17 * MON-FRI"));

另一个开箱即用的实现是一个周期性Trigger ,它接受一个固定的周期、一个可选的初始延迟值,以及一个布尔值,用来指示周期应该解释为固定速率还是固定延迟。由于TaskScheduler接口已经定义了以固定速率或固定延迟调度任务的方法,因此应该尽可能直接使用这些方法。PeriodicTrigger实现的价值在于它可以在依赖于触发器抽象的组件中使用。例如,允许周期性Trigger 、基于cro的Trigger ,甚至自定义Trigger 实现可以互换使用,这可能很方便。这样的组件可以利用依赖注入,这样就可以在外部配置这样的Trigger 。

3.3 TaskScheduler实现

在应用服务器环境中,TaskScheduler提供的灵活性尤其重要。因为在这种环境中,线程不应该由应用程序本身直接创建。对于这种情况,Spring提供了一个TimerManagerTaskScheduler,它将委托给CommonJ TimerManager实例,通常配置为JNDI-lookup。

四、调度和异步执行的注解支持

4.1 开启scheduling 注解功能

为了支持@Scheduled和@Async注释,请将@EnableScheduling和@EnableAsync添加到@Configuration类中

@Configuration

@EnableAsync

@EnableSCheduling

public class AppConfig {

}

你可以自由选择应用程序的相关注释。例如,如果只需要支持@Scheduled,那么只需省略@EnableAsync即可。对于更细粒度的控制,可以另外实现调度器和/或AsyncConfigurer接口。

如果你更喜欢xml配置,这样配置。

}

4.2 @Scheduled

@Scheduled添加到方法上

//上一次调用完之后,五秒再调用一次,依此循环下去

@Scheduled(fixedDelay=5000)

public void doSomething() {

// something that should execute periodically

}

//连续的每次调用开始时间之间,间隔5s

@Scheduled(fixedRate=5000)

public void doSomething() {

// something that should execute periodically

}

//

@Scheduled(cron="*/5 * * * * MON-FRI")

public void doSomething() {

// something that should execute on weekdays only

}

值得注意的是调度的方法返回值必须是void,并且不能期望有任何参数。如果方法需要与来自应用程序上下文的其他对象交互,那么这些对象通常是通过依赖注入提供的。

4.3 @Async注解

添加了@Async注解的方法会异步执行。换句话说,方法调用后会立即返回,方法的实际执行将发生在提交给Spring TaskExecutor的任务中。

@Async

void doSomething() {

// this will be executed asynchronously

}

/@Scheduled注释的方法不同,这些方法可以预期参数.

//因为调用方将在运行时以“正常”方式调用它们,而不是从容器管理的调度任务中调用。

@Async

void doSomething(String s) {

// this will be executed asynchronously

}

// 具有Future回调返回值

//执行其它任务的优先级 依然是高于执行回调的优先级。

@Async

Future returnSomething(int i) {

// this will be executed asynchronously

}

4.4 指定@Async注解的执行器

默认情况下,在方法上指定@Async时,将使用的执行器是提供“annotation-driven”元素的执行器,如上所述。然而,当需要指示在执行给定方法时应该使用非默认的执行器时,可以使用@Async注释的值属性。

@Async("otherExecutor")

void doSomething(String s) {

// this will be executed asynchronously by "otherExecutor"

}

五、Task 命名空间

从Spring 3.0开始,有一个用于配置TaskExecutor和TaskScheduler实例的XML名称空间。并提供了一种方便的方法,可以将任务配置为使用触发器进行调度。

5.1 scheduler 元素

id属性用作线程池中线程的前缀名。如果不指定pool-size,默认的线程池中只有一个线程。

5.2 executor元素

与上面的调度器一样,为'id'属性提供的值将用作池中线程名称的前缀。就池大小而言,'executor'元素比'scheduler'元素支持更多的配置选项。首先,ThreadPoolTaskExecutor的线程池本身是可配置的。执行程序的线程池可能对核心和最大大小有不同的值,而不仅仅是单个大小。如果提供了单个值,那么执行器将拥有一个固定大小的线程池(核心和最大大小相同)。然而,“executor”元素的“池大小”属性也接受“min-max”形式的范围。

pool-size="5-25"

queue-capacity="100"/>

pool-size="5-25"

queue-capacity="100"

rejection-policy="CALLER_RUNS"/>

5.3 scheduled-tasks元素

Spring task namespace 最强大的特性是支持在Spring应用程序上下文中配置要调度的任务。这与Spring中的其他“方法调用者”类似,例如JMS名称空间提供的配置消息驱动pojo的方法。

六、Quartz Scheduler

Quartz使用触发器、作业和作业细节对象来实现各种作业的调度。有关Quartz背后的基本概念,请参阅http://quartz-scheduling er.org。为了方便起见,Spring提供了两个类,它们简化了基于Spring的应用程序中Quartz的使用。

6.1 使用JobDetailBean

JobDetail对象包含运行作业所需的所有信息。Spring框架提供了JobDetailBean,它使JobDetail更接近于具有合理默认值的实际JavaBean。

job detail bean 具有运行作业(ExampleJob)所需的所有信息。timeout在job data map指定。job data map可以通过JobExecutionContext(在执行时传递给您)获得,但是JobDetailBean还将 job data map 中的属性映射到实际job的属性。因此,在本例中,如果ExampleJob包含一个名为timeout的属性,JobDetailBean将自动应用它。

package example;

public class ExampleJob extends QuartzJobBean {

private int timeout;

/**

* Setter called after the ExampleJob is instantiated

* with the value from the JobDetailBean (5)

*/

public void setTimeout(int timeout) {

this.timeout = timeout;

}

protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {

// do the actual work

}

}

6.2 使用MethodInvokingJobDetailFactoryBean

使用MethodInvokingJobDetailFactoryBean你可以调用特定对象上的方法。

使用上面的配置将会导致ExampleBusinessObject .doIt()方法被调用。

public class ExampleBusinessObject {

// properties and collaborators

public void doIt() {

// do the actual work

}

}

使用MethodInvokingJobDetailFactoryBean,不再需要创建只调用一个方法的一行作业,只需要创建实际的业务对象并连接到它。

默认情况下,Quartz作业是无状态的,导致作业相互干扰的可能性。如果为相同的JobDetail指定两个触发器,那么可能在第一个作业完成之前,第二个作业就会开始。如果JobDetail类实现有状态接口,则不会发生这种情况。在第一项工作完成之前,第二项工作不会开始。要使方法调用jobdetailfactorybean产生的作业非并发,请将并发标志设置为false。

6.3 作业调度

尽管我们能使用MethodInvokingJobDetailFactoryBean调用特定对象上的方法,但是我们还是需要调度作业 。这需要使用触发器和scheduler erfactorybean完成。Quartz 提供了多种触发器

Spring提供了两种Quartz 工厂对象:

CronTriggerFactoryBean

SimpleTriggerFactoryBean

两种触发器的示例

关于SchedulerFactoryBean的等多属性设置 ,参考SchedulerFactoryBean javadoc

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

java单线程任务调度_一文详解Spring任务执行和调度(小结)相关推荐

  1. oracle trigger 延迟执行_一文详解Spring任务执行和调度

    一.概述 Spring框架分别使用TaskExecutor和TaskScheduler接口提供异步执行和任务调度的抽象.Spring还提供了这些接口的实现,这些接口支持线程池或将其委托给应用服务器环境 ...

  2. java data使用_@Data注解详解及使用方法-Fun言

    @Data作用 去除Getter,Setter,equals,hashCode,toString方法,@Data注解在类上时,简化java代码编写,为该类提供读写属性.简单来说就是不用再手动添加get ...

  3. 没有执行此操作所需的足够可用空间。_一文详解 MySQL 高可用之 DRBD | 原力计划...

    作者 | wzy0623责编 | 屠敏出品 | CSDN 博客大多数MySQL高可用解决方案都是基于MySQL自带的各种复制技术.本质上是将一个实例上的数据更新或事务,在其它实例上进行重放,从而完成数 ...

  4. Java 启动和停止界面_一文详解各种花里胡哨的Java调试技巧,多图预警,记得收藏...

    欢迎关注专栏<Java架构筑基>--专注于Java技术的研究与分享! Java架构筑基​zhuanlan.zhihu.com Java架构筑基--专注于Java技术的研究与分享! 后续文章 ...

  5. java中间件登陆超时_一文详解 Java 的几把 JVM 级锁

    作者 | 楚昭 来源 | 阿里巴巴中间件(ID:Aliware_2018) 在计算机行业有一个定律叫"摩尔定律",在此定律下,计算机的性能突飞猛进,而且价格也随之越来越便宜, CP ...

  6. java 可选参数_超干货详解:kotlin(4) java转kotlin潜规则

    往期推荐 如果面试时大家都说真话... 这400道面试题,决定了你去BAT还是TMD 前言 以一个java老鸟的角度,如何去看 kotlin. Java源代码应该如何用Kotlin重构. 如何正确学习 ...

  7. R 多变量数据预处理_超长文详解:C语言预处理命令

    一  前言 预处理(或称预编译)是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作.预处理指令指示在程序正式编译前就由编译器进行的操作,可放在程序中任何位置. 预处理是C语言的一个重要功能 ...

  8. 狄利克雷分布公式_一文详解隐含狄利克雷分布(LDA)

    一.简介 隐含狄利克雷分布(LatentDirichletAllocation,简称LDA)是由DavidM.Blei.AndrewY.Ng.MichaelI.Jordan在2003年提出的,是一种词 ...

  9. java 缓冲区溢出_缓冲区溢出详解

    1 缓冲区溢出原理 缓冲区是一块连续的计算机内存区域,可保存相同数据类型的多个实例.缓冲区可以是堆栈(自动变量).堆(动态内存)和静态数据区(全局或静态).在C/C++语言中,通常使用字符数组和mal ...

  10. nacos 本地测试_一文详解 Nacos 高可用特性

    简介:我今天介绍的 Nacos 高可用,是 Nacos 为了提升系统稳定性而采取的一系列手段.Nacos 的高可用不仅仅存在于服务端,同时也存在于客户端,以及一些与可用性相关的功能特性中,这些点组装起 ...

最新文章

  1. springboot 主键重复导致数据重复_Springboot实现防重复提交和防重复点击(附源码)...
  2. 精通python爬虫框架-精通Python爬虫从Scrapy到移动应用(文末福利)
  3. Windows CE,你妈吗喊你在多核上玩玩
  4. ajax常见错误和使用总结
  5. 批发电脑配件_2019年10月电脑配件表
  6. 技术人的年货福利:百宝黑皮书在手,2020年技术栈变革一次看透 | 免费下载
  7. [转]编程语言与宗教
  8. 浅谈Spring @Order注解的使用
  9. C语言中char字符为0时的情况,c语言中char的用法
  10. Laravel之数据库操作与Eloquent模型使用总结
  11. 什么是正向代理和反向代理
  12. 基站定位查询api使用接口
  13. 工匠精神消失的手机2020:衰落、变局、绝唱、破圈
  14. Arduino造轮子—FlashSRAM优化代码
  15. 一些学习gis有关的文章
  16. Python requests库Proxy代理问题
  17. 操作系统:内存管理(概念)
  18. ssl证书购买后的认证签发过程
  19. 十四、关于利用卡诺图快速解决时序电路自启动问题的研究
  20. 微带滤波器摘要_滤波器详细分类摘要.ppt

热门文章

  1. 招聘|月薪20-40K|上海莱陆科技招高级机器人、​Android研发工程师
  2. 论文简述 | Voxel Map for Visual SLAM
  3. LeetCode之二分查找
  4. 关于Java的权限修饰符(public,private,protected,默认friendly)
  5. MVC整体流程机制原理概述
  6. Cygwin的进程管理
  7. MSRCRGIMP(基于GIMP版本的多尺度Retinex)
  8. 魔方机器人之下位机编程----串口接收数据并解析
  9. HyperVolume多目标评价指标概述
  10. Latex写论文格式注意点