对于多线程及周期性调度相关的操作,spring框架提供了TaskExecutor和TaskScheduler接口为异步执行和任务调度。并提供了相关实现类给开发者使用。(只记录采用注解的使用形式,对于XML的使用形式不做笔记。)
  
  Spring官方对TaskExecutor的相关解释:
  
  Spring的TaskExecutor接口与java.util.concurrent.Executor接口相同。该接口具有单个方法(execute(Runnable task)),该方法根据线程池的语义和配置接受要执行的任务。
  
  二话(写)不说,自说(写)自话(字)直接拐上了
  
  TaskExecutor接口相关实现类
  
  实现类名 对应解释(直接甩翻译了)
  
  SyncTaskExecutor 该实现类不会执行异步调用。 相反,每次调用都在调用的线程中进行(翻译过来也即同步任务执行器)。 它主要用于不需要多线程的情况,例如在简单的测试用例中。
  
  SimpleAsyncTaskExecutor 此实现不会重用任何线程。 相反,它为每次调用启动一个新线程。 但是,它确实支持并发限制,该限制会阻止超出限制的任何调用,直到释放插槽为止。(说简单了,就是要使用了直接创建一个线程)
  
  ConcurrentTaskExecutor 此实现是java.util.concurrent.Executor实例的适配器。很少需要直接使用ConcurrentTaskExecutor**(官网自己都觉得很少使用,不过相对于ThreadPoolTaskExecutor,官网推荐如果ThreadPoolTaskExecutor不够灵活,无法满足需求,则可以使用ConcurrentTaskExecutor)**。
  
  ThreadPoolTaskExecutor 杀手锏级的任务调度器(最常用),可以说已经足够满足我们的需求了(除非,非常非常特例才使用ConcurrentTaskExecutor)。官网翻译重要片段:公开了bean属性,用于配置java.util.concurrent.ThreadPoolExecutor并将其包装在TaskExecutor中
  
  WorkManagerTaskExecutor 此实现使用CommonJ WorkManager作为其后备服务提供程序,并且是在Spring应用程序上下文中在WebLogic或WebSphere上设置基于CommonJ的线程池集成的中心便利类。
  
  DefaultManagedTaskExecutor 此实现在JSR-236兼容的运行时环境(例如Java EE 7+应用程序服务器)中使用JNDI获取的ManagedExecutorService,为此目的替换CommonJ WorkManager。(说明了就是依赖环境)
  
  其中可能今后工作中会用到的(包括测试) SyncTaskExecutor、SimpleAsyncTaskExecutor、ConcurrentTaskExecutor、ThreadPoolTaskExecutor此四个实现类。重点关注ThreadPoolTaskExecutor此类。
  
  记:以上均实现了spring提供的TaskExecutor**接口。
  
  Spring官方对TaskSheduler接口的相关解释:
  
  用于在将来的某个时间点调度任务。
  
  TaskScheduler接口相关实现类
  
  实现类名 对应解释
  
  ConcurrentTaskScheduler 该类实际继承了ConcurrentTaskExecutor对象。只是实现了TaskScheduler接口,增加了相关定时调度任务的方法。
  
  ThreadPoolTaskScheduler spring对该类设计原则同ThreadPoolTaskExecutor类。是为了定时调度任务不依赖相关的运行容器(例如weblogic、WebSphere等)。其底层委托给ScheduledExecutorService,向外暴露相关的常见bean配置属性。
  
  接下来对以上相应的实现类通过注解的形式进行相应的测试
  
  首先进行解释要用到的几个注解,对这几个注解总结如下表
  
  注解名 解释
  
  @EnableAsync 开启异步执行。官方文档中解释:该注解添加到@Configuration标注的类上以开始异步执行。开启后@Async标注的方法或类即可异步执行。
  
  @EnableScheduling 开启定时调度。官方文档解释也是配合@Configuration一起使用。开启后@Scheduled注解标注的方法即可自动定时(或延迟)执行。
  
  @Async 异步执行注解。可标注类和方法。标注类时,则该类下所有方法均可使用异步执行。标注方法时,则该方法可使用异步执行。当标注有@Configuration注解的配置类上标注了@EnableAsync注解后即可生效。
  
  @Scheduled 标注相关方法后,如果配置类标注了@EnableScheduling后即可开启定时调度任务。
  
  接下来先测试异步执行器(TaskExecutor)
  
  使用方式1(直接使用spring容器中的ThreadPoolTaskExecutor):
  
  先通过@Bean注解将ThreadPoolTaskExecutor放入Spring容器中:
  
  @Configuration
  
  public class ExecutorBean {
  
  /**
  
   * 执行器ThreadPoolTaskExecutor
  
   */
  
  @Bean
  
  public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
  
  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  
  executor.setCorePoolSize(10); // 设置核心线程池大小(这里设置为初始化10个)
  
  executor.setMaxPoolSize(30); // 设置最大线程池大小(当核心线程池不够用时候,会自动在原基础上增加。最大为30个)
  
  executor.setQueueCapacity(2000); // 设置队列容量为2000个。
  
  return executor;
  
  然后在标注有@Configuration注解的配置类或SpringBoot启动类上添加@EntityAsync注解。这里在标有@SpringBootApplication注解的SpringBoot启动类的入口方法上添加@EntityAsync注解。
  
  @SpringBootApplication
  
  @EnableAsync
  
  public class ScheduleApplication {
  
  public static void main(String[www.tongqt178.com] args) {
  
  SpringApplication.run(ScheduleApplication.class, args);
  
  然后在需要采取异步执行的方法上(或类上,此测试使用方法)标注@Async注解:
  
  @Async(value="threadPoolTaskExecutor")
  
  public void testThreadPoolTaskExecutor() {
  
  System.err.println("--- testThreadPoolTaskExecutor --");
  
  测试用例:
  
  @Test
  
  public void testThreadPoolTaskExecutor() {
  
  System.err.println("--- 开始 ---");
  
  taskExecutorService.testThreadPoolTaskExecutor();
  
  System.err.println("--- 结束 ---");
  
  执行结果:
  
  --- 开始 ---
  
  --- 结束 ---
  
  --- testThreadPoolTaskExecutor --
  
  使用方式2(通过修改默认的线程池配置,即实现AsyncConfigurer接口,并重写其中的getAsyncExecutor方法[因为是JDK8提供的default方法,所以才称为重写]):
  
  首先,先实现AsyncConfigurer接口,重写getAsyncExecutor方法并将此实现类作为配置类装载进spring容器中(记:对于void返回类型,异常未被捕获且无法传输,所以getAsyncUncaughtExceptionHandler方法用于处理异步调用后出现异常的情况。这里仅仅记录未出现异常的测试),同时添加@EnableAsync开启可异步调用(也可以在springBoot启动类中的入口方法上添加)。
  
  @Configuration
  
  @EnableAsync
  
  public class CustomAsyncConfigurer implements AsyncConfigurer {
  
  /**
  
   * 设置线程池相关的配置
  
   * @return ThreadPoolTaskExecutor
  
   */
  
  @Override
  
  public Executor getAsyncExecutor() {
  
  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  
  executor.setCorePoolSize(10); // 设置核心线程池大小(这里设置为初始化10个)
  
  executor.setMaxPoolSize(30); // 设置最大线程池大小(当核心线程池不够用时候,会自动在原基础上增加。最大为30个)
  
  executor.setQueueCapacity(2000); // 设置队列容量为2000个。
  
  executor.initialize();
  
  return executor;
  
  然后可以直接使用@Async注解标注需要异步执行的方法(或类上,此测试使用方法)
  
  @Async
  
  public void testThreadPoolTaskExecutor(Long id) {
  
  System.err.println("--- testThreadPool www.mingheyl178.com/ TaskExecutor --" + id);
  
  测试用例:
  
  @Test
  
  public void testThreadPoolTaskExecutor() {
  
  System.err.println("--- 开始前 ---");
  
  System.err.println("--- 开始 ---");
  
  for(int i =0;i<20;i++) {
  
  taskExecutorService.testThreadPoolTaskExecutor(new Long(i));
  
  }
  
  System.err.println("--- 结束 ---");
  
  System.err.println("--- 结束后 ---");
  
  --- 开始前 ---
  
  --- 开始 ---
  
  --- testThreadPoolTaskExecutor --0
  
  --- testThreadPoolTaskExecutor --1
  
  --- testThreadPoolTaskExecutor --2
  
  --- testThreadPoolTaskExecutor --3
  
  --- testThreadPoolTaskExecutor --4
  
  --- testThreadPoolTaskExecutor --5
  
  --- testThreadPoolTaskExecutor --6
  
  --- testThreadPoolTaskExecutor --7
  
  --- testThreadPoolTaskExecutor --8
  
  --- testThreadPoolTaskExecutor --9
  
  --- testThreadPoolTaskExecutor --10
  
  --- testThreadPoolTaskExecutor --11
  
  --- testThreadPoolTaskExecutor --12
  
  --- testThreadPoolTaskExecutor --13
  
  --- testThreadPoolTaskExecutor --14
  
  --- testThreadPoolTaskExecutor --17
  
  --- testThreadPoolTaskExecutor --16
  
  --- testThreadPoolTaskExecutor --15
  
  --- 结束 ---
  
  --- 结束后 ---
  
  --- testThreadPoolTaskExecutor --19
  
  --- testThreadPoolTaskExecutor --18
  
  **使用方式3:因为ThreadPoolTaskScheduler实现了TaskExecutor相关的接口。所以同样可以用ThreadPoolTaskScheduler替换ThreadPoolTaskExecutor来调用异步执行器。
  
  同样实现AsyncConfigurer接口,重写getAsyncExecutor方法并将此实现类作为配置类装载进spring容器中。只是此时用ThreadPoolTaskScheduler替换ThreadPoolTaskExecutor类作为任务执行器
  
  @Configuration
  
  @EnableAsync
  
  public class CustomAsyncConfigurer implements AsyncConfigurer {
  
  /**
  
  * 设置线程池相关的配置
  
  * @return ThreadPoolTaskExecutor
  
  */
  
  @Override
  
  public Executor getAsyncExecutor() {
  
  ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
  
  executor.setPoolSize(30);
  
  executor.initialize();
  
  return executor;
  
  然后用@Asnyc标注方法
  
  @Async
  
  public void testThreadPoolTaskScheduler(Long id) {
  
  System.err.println("--- testThreadPoolTaskExecutor --" + id);
  
  @Test
  
  public void testThreadPoolTaskScheduler() {
  
  System.err.println("--- 开始前 ---");
  
  System.err.println("--- 开始 ---");
  
  for(int i =0;i<20;i++) {
  
  taskExecutorService.testThreadPoolTaskScheduler(new Long(i));
  
  }
  
  System.err.println("--- 结束 ---");
  
  System.err.println("--- 结束后 ---");
  
  经过测试,用例3没啥效果...测试方式可能有误。同样的异步调用ThreadPoolTaskScheduler类可能不能当做ThreadPoolTaskExecutor 类使用。虽然同样实现了TaskExecutor接口(看来得看底层源码了,现在仅仅记录下来先)
  
  现在来测试定时调度器(TaskScheduler)
  
  使用方式1(直接使用@EnableScheduling开启定时调度任务,然后对需要定时调度的方法用@Sheduled注解标注):
  
  直接在SpringBoot启动器类中的入口方法上标注或标注了@Configuration注解的配置类上使用@EnableScheduling注解
  
  //在启动类上添加
  
  @SpringBootApplication
  
  @EnableScheduling
  
  public class ScheduleApplication {
  
  public static void main(String[] args) {
  
  SpringApplication.run(ScheduleApplication.class, args);
  
  }
  
  }
  
  //或在在配置类上标注
  
  @Configuration
  
  @EnableScheduling
  
  public class CustomScheduleConfigurer implements AsyncConfigurer {
  
  需要在定时任务的方法上添加@Scheduled
  
  @Scheduled(fixedRate = 300) //表示每300毫秒调用一次该方法
  
  @Override
  
  public void threadPoolTaskScheduler() {
  
  System.err.println("--- threadPoolTaskScheduler --");
  
  测试用例
  
  @Test
  
  public void schedulers() throws Exception {
  
  Thread.sleep(50000000); //让线程睡上一段时间,以便查看效果
  
  因为应用一启动后定时调度器便会开始执行。如果测试用例不使用线程睡眠的话程序会一瞬间执行结束,有可能看不到效果。
  
  记:@Scheduled注解支持Quartz的CRON表达式来规划定时任务(仅做记录:SPRING官网示例)。
  
  spring框架支持Quartz来使用定时调度任务。
  
  使用方式2(实现SchedulingConfigurer配置类,规定定时任务)
  
  首先实现SchedulingConfigurer配置类,并启用定时调度任务
  
  @Configuration
  
  @EnableScheduling
  
  public class CustomSchedulerConfigurer implements SchedulingConfigurer {
  
  @Override
  
  public void configureTasks(www.michenggw.com ScheduledTaskRegistrar taskRegistrar) {
  
  IntervalTask task = new IntervalTask(new Runnable() {
  
  @Override
  
  public void run() {
  
  System.err.println("----间隔执行----");
  
  }
  
  }, 2000);
  
  taskRegistrar.addFixedDelayTask(task); //taskRegistrar有更多相关方法来执行定时调度任务。测试用例先做简单记录
  
  然后进行测试
  
  @Test
  
  public void schedulers() throws Exception {
  
  Thread.sleep(50000000); //同样让线程睡上一段时间,以便查看效果
  
  测试中并未处理异步执行后如果出现异常的情况。异常情况发生后如何处理之后再做记录。

spring任务执行器与任务调度器(TaskExecutor And TaskScheduler)的更多相关文章

  1. 基于Spring Task的定时任务调度器实现

    在很多时候,我们会需要执行一些定时任务 ,Spring团队提供了Spring Task模块对定时任务的调度提供了支持,基于注解式的任务使用也非常方便. 只要跟需要定时执行的方法加上类似 @Schedu ...

  2. Spring任务执行器(TaskExecutor)

    Spring任务执行器(TaskExecutor)    Spring通州任务执行器(TaskExecutor)来实现多线程和并发编程,使用ThreadPoolTaskExecutor可实现一个基于线 ...

  3. springMVC + quartz实现定时器(任务调度器)

    首先我们要知道任务调度器(定时器)有几种,这边我会写三种 第一种是基于JDK的本身的一个定时器(优点:简单,缺点:满足不了复杂的需求) package com.timer1; import java. ...

  4. 开源基于docker的任务调度器pipeline,比`quartzs` 更强大的分布式任务调度器

    pipeline 分布式任务调度器 目标: 基于docker的布式任务调度器, 比quartzs,xxl-job 更强大的分布式任务调度器. 可以将要执行的任务打包为docker镜像,或者选择已有镜像 ...

  5. TaskScheduler一个.NET版任务调度器

    TaskScheduler是一个.net版的任务调度器.概念少,简单易用. 支持SimpleTrigger触发器,指定固定时间间隔和执行次数: 支持CronTrigger触发器,用强大的Cron表达式 ...

  6. 21 BasicTaskScheduler基本任务调度器(一)——Live555源码阅读(一)任务调度相关类

    21_BasicTaskScheduler基本任务调度器(一)——Live555源码阅读(一)任务调度相关类 BasicTaskScheduler基本任务调度器 BasicTaskScheduler基 ...

  7. 18 TaskScheduler任务调度器抽象基类——Live555源码阅读(一)任务调度相关类

    这是Live555源码阅读的第二部分,包括了任务调度相关的三个类.任务调度是Live555源码中很重要的部分. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/ol ...

  8. Spring AOP原理及拦截器

    原理 AOP(Aspect Oriented Programming),也就是面向方面编程的技术.AOP基于IoC基础,是对OOP的有益补充. AOP将应用系统分为两部分,核心业务逻辑(Core bu ...

  9. azkaben任务调度器

    azkaban学习笔记总结 01.工作流调度器azkaban 1. 任务调度概述 一个完整的数据分析系统通常都是由大量任务单元组成: shell脚本程序,java程序,mapreduce程序.hive ...

随机推荐

  1. MyBatis-参数处理

    1.单个参数 mybatis不会做特殊处理. #{参数名/任意名}:取出参数值. 2.多个参数 mybatis会做特殊处理. 多个参数会被封装成 一个map. key:param1...paramN, ...

  2. Omad群组部署、依赖部署一键解决

    本文来自网易云社区 作者:李培斌 前言 基于omad部署平台实现一键部署的实践已有很多成功的经验,杭研QA的技术先锋们也在ks圈里有很多不同的文章去阐述关于这类需求的实现和思路,当然包括我们金融事业部 ...

  3. Oracle TDE的学习

    TDE的开启和关闭 设置wallet目录,在参数文件sqlnet.ora中,按照下面的格式加入信息 # Oracle Advanced Security Transparent Data Encryp ...

  4. 仿京东淘宝商品详情页属性选择js效果

    在网上找了好久发现都不符合要求就自己摸索写了一个,用到了linq.js这个linq to js 扩展,不然用纯JS遍历json查询要死人啊 demo:http://123.207.28.46:8086 ...

  5. Ajax中post请求和get请求的区别

    首先提出两点Post比Get大的不同地方 1.post请求浏览器每次不会缓存,每次都会重新请求,而get请求不要缓存的时候,需要手动设置 写上xhr.setRequestHeader("If ...

  6. String、StringBuffer、StringBuilder的区别和解析

    1.三个类之间的关系 他们都是通过字符数组来实现的,继承关系 String:字符串常量,不可变类 StringBuffer:字符串变量,可变类,线程安全 StringBuilder:字符串变量,可变类 ...

  7. 「日常训练」Case of Matryoshkas(Codeforces Round #310 Div. 2 C)

    题意与分析(CodeForces 556C) 为了将所有\(n\)个娃娃编号递增地串在一起(原先是若干个串,每个串是递增的), 我们有两种操作: 拆出当前串中最大编号的娃娃(且一定是最右边的娃娃). ...

  8. 韦大仙--简单的monkey测试命令行操作及生成log日志保存

    作中,在将apk交给软件测试人员去测试之前,不免要自己先自测,monkey自测是一个不错的选择! 步骤很简单: 1.测试用的手机与电脑连接好USB ,并且安装好驱动(我一般都是通过豌豆荚自动安装的)! ...

  9. 第四模块:网络编程进阶&数据库开发 第1章·网络编程进阶

    01-进程与程序的概念 02-操作系统介绍 03-操作系统发展历史-第一代计算机 04-操作系统发展历史-批处理系统 05-操作系统发展历史-多道技术 06-操作系统发展历史-分时操作系统 07-总结 ...

  10. 第4章 TCP/IP通信案例:访问Internet上的Web服务器

    第4章 TCP/IP通信案例:访问Internet上的Web服务器 4.2 部署代理服务器 书中为了演示访问Internet上的Web服务器的全过程,使用了squid代理服务器程序模拟了一个代理服务器 ...