1、定时任务简述:指定触发规则后,按照一定的频率自动往复执行。默认只有一个单例化的线程池(始终只有一个线程)
去处理定时任务;只有一个线程时,多个任务需要并行(同时)执行时会产生时间差【每个任务从执行开始
到结束需要的时间不同,单线程情况下,只能等前一个任务结束才能开始执行下一个任务】,导致实际
上每个任务不是按照指定的指定的频率执行。可以通过配置线程池来解决。
1.1、非异步定时任务:从任务开始到结束都是同一个线程(即使执行过程中有线程阻塞)
【当前任务执行完毕后,才会根据任务执行条件再次触发】
异步定时任务(方法上有@Asycn注解): 从任务开始,假设进入阻塞状态,任务结束时和任务开始时不一定是
同一个线程处理的【当前任务没有执行完毕,但任务执行条件触发则直接创建新线程执行任务】
2、相关依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.12.RELEASE </version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.3</version> </dependency>
3、 简要的配置说明
3.1添加命名空间
xmlns:task="http://www.springframework.org/schema/task http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
3.2 spring配置文件【该文件需要spring读取】
<!-- 定时任务,配置需要扫描的包 -->
<context:component-scan base-package="com.demo.quartz" />
<!-- 用于激活那些已经在spring容器里注册过的bean(无论是通过xml的方式还是通过package scanning的方式)上面的注解 可不配置 --> <context:annotation-config/>
<!-- 配置处理定时任务的线程池 --> <task:scheduler id="scheduler" pool-size="10" />
<!-- 配置处理 异步定时任务的 线程池 -->
<!--
pool-size:线程池大小 keep-alive:线程最大空闲时间
queue-capacity:队列大小(无线程可用时,其余任务放置队列中,队列放满后其他任务只能等待)
rejection-policy:队列任务数达到最大时,处理其他任务的策略
--> <task:executor id="taskExecutor" pool-size="10" keep-alive="2000" rejection-policy="DISCARD_OLDEST"
queue-capacity="10" />
<!-- 配置spring定时开关--> <task:annotation-driven executor="taskExecutor" scheduler="scheduler" />
3.3、@Scheduled注解中属性设置
cron:执行任务触发频率规则:cron表达式详情查看另一博主介绍:http://biaoming.iteye.com/blog/39532
@Scheduled(fixedRate=3000) //上一次任务 开始执行后3秒 再次执行 @Scheduled(fixedDelay=3000) //上一次 任务执行结束后 3秒,再次执行 @Scheduled(initialDelay=1000,fixedDelay=3000) //第一次延时1秒执行,以后每次任务执行完后3秒再次执行
4、简单demo
package com.demo.quartz; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component @EnableScheduling //开启spring定时任务 @Lazy(false) //默认是true为懒下载,此处设置false public class TestQuartz { @Scheduled(cron="0/1 * * * * ?") public void test1() { //AsyncConfigurer // ThreadPoolTaskScheduler tpt = new ThreadPoolTaskScheduler(); // System.err.println(tpt.getPoolSize()); //org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean //SchedulingConfigurer try { // 源码相关的类 //ScheduledExecutorService //ScheduledTaskRegistrar //TaskScheduler //ThreadPoolTaskScheduler //ThreadPoolTaskExecutor //org.springframework.scheduling.config.ScheduledTaskRegistrar; Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss"); System.out.println(Thread.currentThread().getName()+"----------1-----------"+sdf.format(new Date())); } @Scheduled(cron="0/1 * * * * ?") public void test2() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss"); System.out.println(Thread.currentThread().getName()+"----------3-----------"+sdf.format(new Date())); } @Scheduled(cron="0/1 * * * * ?") public void test3() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss"); System.out.println(Thread.currentThread().getName()+"----------4-----------"+sdf.format(new Date())); } @Async @Scheduled(cron="0/1 * * * * ?") public void test4() { SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss"); try { System.err.println(Thread.currentThread().getName()+"----------2-----------查看线程名称-阻塞前"+sdf.format(new Date())); Thread.sleep(3000); System.err.println(Thread.currentThread().getName()+"----------2-----------查看线程名称-阻塞后"+sdf.format(new Date())); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"----------2-----------"+sdf.format(new Date())); } @Async @Scheduled(cron="0/1 * * * * ?") public void test5() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss"); System.out.println(Thread.currentThread().getName()+"----------5-----------"+sdf.format(new Date())); } @Async @Scheduled(cron="0/1 * * * * ?") public void test6() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss"); System.out.println(Thread.currentThread().getName()+"----------6-----------"+sdf.format(new Date())); } }
5、效果图
--------------该数字(表示的任务编号)-----------------------
6、定时任务执行流程源码解析
https://unmi.cc/spring-schedule-runner-threads/