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/