Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("TestThreadWait is called!");
try {
// 使用线程休眠来实现周期执行
Thread.sleep(1000 * 3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
myThread.start();
package com.changan.test;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String[] args) {
/*Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("执行定时任务");
}
},1000,1000);*/
TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("TimerTask is called!");
}
};
Timer timer = new Timer();
/*
* schedule 和 scheduleAtFixedRate 区别:
* 可将schedule理解为scheduleAtFixedDelay,
* 两者主要区别在于delay和rate
* 1、schedule,如果第一次执行被延时(delay),
* 随后的任务执行时间将以上一次任务实际执行完成的时间为准
* 2、scheduleAtFixedRate,如果第一次执行被延时(delay),
* 随后的任务执行时间将以上一次任务开始执行的时间为准(需考虑同步)
*
* 参数:1、任务体 2、延时时间(可以指定执行日期)3、任务执行间隔时间
*/
// timer.schedule(task, 0, 1000 * 3);
timer.scheduleAtFixedRate(task, 0, 1000 * 3);
}
}
package com.changan.test;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
System.out.println("ScheduledExecutorService Task is called!");
}
};
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 参数:1、任务体 2、首次执行的延时时间
// 3、任务执行间隔 4、间隔时间单位
service.scheduleAtFixedRate(runnable, 0, 3, TimeUnit.SECONDS);
}
}
四、@Schedule
1、配置
在spring boot的启动类上加@EnableScheduling注解,允许支持@Scheduled:
@SpringBootApplication
@EnableScheduling
public class Quartz01Application {
public static void main(String[] args) {
SpringApplication.run(Quartz01Application.class, args);
}
}
2、任务类
@Component
public class ScheduleTask {
// 每隔5秒执行一次
@Scheduled(cron = "0/5 * * * * ?")
public void printSay() {
System.out.println("每隔5秒执行一次:" + new Date());
}
}
quartz是一种基于java实现的任务调度框架,可以定时自动的执行你想要执行的任何任务。
quartz官网:http://www.quartz-scheduler.org/
二、Quartz的组成
任务Job(你要做什么事? 将要执行的操作)
job就是你想要实现的任务类,每一个job必须实现org.quartz.job接口。
触发器Trigger(你什么时候去做? cron表达式)
Trigger为你执行任务的触发器,比如你想每天定时3点发送一份统计邮件,Trigger将会设置3点进行执行该任务。
调度器Scheduler(你什么时候需要做什么事?)
Scheduler为任务的调度器,它会将任务job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行Job。
搭建 quartzmaven 项目
项目名为 quartzmaven
添加依赖
<dependencies>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
<version>2.3.2version>
dependency>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartz-jobsartifactId>
<version>2.3.2version>
dependency>
dependencies>
定义 PrintTimeJob 任务类 进行打印当前时间操作
package com.cp.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author : CP
* @version: 1.0
* @program : quartzmaven
* @description : 打印时间
* @date : 2021-03-20 10:11
**/
public class PrintTimeJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//获取当前系统时间
Date date = new Date();
//定义时间格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//将获取的系统时间根据定义的时间格式进行格式化
String format = simpleDateFormat.format(date);
//根据定义的时间格式打印获取的时间
System.out.println("执行定时任务,当前时间为:"+format);
}
}
创建 PrintTimeSchedulerDemo 类 进行 打印时间表计划演示
package com.cp.test;
import com.cp.job.PrintTimeJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
/**
* @author : CP
* @version: 1.0
* @program : quartzmaven
* @description : 调用打印时间
* @date : 2021-03-20 10:18
**/
public class PrintTimeSchedulerDemo {
public static void main(String[] args) throws SchedulerException {
//1、调度器(Schedular),从工厂中获取调度实例(默认:实例化new StdSchedulerFactory();)
Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
//2、任务实例(JobDetail)
//加载任务类,与HelloJob完成绑定,要求HelloJob实现Job接口
JobDetail jobDetail= JobBuilder.newJob(PrintTimeJob.class)
//参数1:任务的名称(唯一实例);参数2:任务组的名称
.withIdentity("job1","group1")
.build();
//3、触发器(Trigger)
Trigger trigger= TriggerBuilder.newTrigger()
//参数1:触发器的名称(唯一实例);参数2:触发器组的名称
.withIdentity("trigger1","group1")
//马上启动触发器
.startNow()
//每5秒执行一次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
.build();
//让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
scheduler.scheduleJob(jobDetail,trigger);
//启动
scheduler.start();
}
}
运行结果如下图:
项目名为 quartz-boot
不勾选依赖
添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-quartzartifactId>
dependency>
在主启动类添加 @EnableScheduling 注解
package com.cp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling //添加注解
public class QuartzBootApplication {
public static void main(String[] args) {
SpringApplication.run(QuartzBootApplication.class, args);
}
}
package com.cp.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author : CP
* @version: 1.0
* @program : quartz-boot
* @description :
* @date : 2021-03-20 10:34
**/
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//获取当前系统时间
Date date = new Date();
//定义时间格式
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//将获取的系统时间根据定义的时间格式进行格式化
String format = simpleDateFormat.format(date);
//根据定义的时间格式打印获取的时间
System.out.println("执行定时任务,当前时间为:"+format);
}
}
package com.cp.config;
import com.cp.job.QuartzJob;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
/**
* Quartz配置类
*/
@Configuration
public class QuartzConfig {
/**
* 1、创建Job对象
*/
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();
//关联我们自己的Job类
factoryBean.setJobClass(QuartzJob.class);
return factoryBean;
}
/**
* 2、创建Trigger对象
*/
@Bean
public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
SimpleTriggerFactoryBean factoryBean=new SimpleTriggerFactoryBean();
//关联JobDetail对象
factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
//该参数表示一个执行的毫秒数
factoryBean.setRepeatInterval(2000); //每隔2秒执行一次
//重复次数
factoryBean.setRepeatCount(5);
return factoryBean;
}
/**
* 3、创建Scheduler
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean){
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
//关联trigger
factoryBean.setTriggers(simpleTriggerFactoryBean.getObject());
return factoryBean;
}
}
在quartz-boot项目上的基础添加依赖
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.13version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
<version>2.2version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
package com.cp;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.apache.commons.lang3.StringUtils;
import java.util.Scanner;
/**
* @author : CP
* @version: 1.0
* @program : xinguan-parent
* @description : 框架构造
* @date : 2020-11-30 21:19
**/
public class CodeGenerator {
/**
*
* 读取控制台内容
*
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 创建代码生成器对象
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
gc.setOutputDir(scanner("请输入你的项目路径") + "/src/main/java");
gc.setAuthor("cp");
//生成之后是否打开资源管理器
gc.setOpen(false);
//重新生成时是否覆盖文件
gc.setFileOverride(false);
//%s 为占位符
//mp生成service层代码,默认接口名称第一个字母是有I
gc.setServiceName("%sService");
//设置主键生成策略 自动增长
gc.setIdType(IdType.AUTO);
//设置Date的类型 只使用 java.util.date 代替
gc.setDateType(DateType.ONLY_DATE);
//开启实体属性 Swagger2 注解
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
//使用mysql数据库
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("请输入模块名"));
pc.setParent("com.cp");
pc.setController("controller");
pc.setService("service");
pc.setServiceImpl("service.impl");
pc.setMapper("mapper");
pc.setEntity("entity");
pc.setXml("mapper");
mpg.setPackageInfo(pc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//设置哪些表需要自动生成
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
//实体类名称驼峰命名
strategy.setNaming(NamingStrategy.underline_to_camel);
//列名名称驼峰命名
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//使用简化getter和setter
strategy.setEntityLombokModel(true);
//设置controller的api风格 使用RestController
strategy.setRestControllerStyle(true);
//驼峰转连字符
strategy.setControllerMappingHyphenStyle(true);
//去除前置,不需要可以不填写,可以用逗号添加多个
strategy.setTablePrefix("biz_");
mpg.setStrategy(strategy);
mpg.execute();
}
}
spring:
application:
name: quartz-boot
# 数据源配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?userUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username: root
password: root
# 格式化时区
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
# jackson实体转json时 为NULL不参加序列化的汇总
default-property-inclusion: non_null
# 配置端口号
server:
port: 8081
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
#逻辑删除
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
# 扫描 Mapper.xml
mapper-locations: classpath*:/mapper/*.xml
# 配置别名
type-aliases-package: com.cp.api.entity
package com.cp;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@MapperScan("com.cp.api.mapper")
@EnableScheduling
public class QuartzBootApplication {
public static void main(String[] args) {
SpringApplication.run(QuartzBootApplication.class, args);
}
}
package com.cp.config;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.stereotype.Component;
//将该类实例化,使得可以直接用
@Component("myadaptableJobFactory")
public class MyadaptableJobFactory extends AdaptableJobFactory {
//AutowireCapableBeanFactory可以将一个对象添加到Spring IOC容器中,并且完成该对象注入
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
//该方法将实例化的任务对象手动的添加到SpringIOC容器中并且完成对象的注入
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object object = super.createJobInstance(bundle);
//将object对象添加到Spring IOC容器中并完成注入
this.autowireCapableBeanFactory.autowireBean(object);
return object;
}
}
//注入myadaptableJobFactory类
@Autowired
private MyadaptableJobFactory myadaptableJobFactory;
//在 schedulerFactoryBean 方法后添加
factoryBean.setJobFactory(myadaptableJobFactory);
完整代码
package com.cp.config;
import com.cp.job.QuartzJob;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
/**
* Quartz配置类
*/
@Configuration
public class QuartzConfig {
@Autowired
private MyadaptableJobFactory myadaptableJobFactory;
/**
* 1、创建Job对象
*/
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();
//关联我们自己的Job类
factoryBean.setJobClass(QuartzJob.class);
return factoryBean;
}
/**
* 2、创建Trigger对象
*/
@Bean
public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
SimpleTriggerFactoryBean factoryBean=new SimpleTriggerFactoryBean();
//关联JobDetail对象
factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
//该参数表示一个执行的毫秒数
factoryBean.setRepeatInterval(2000); //每隔2秒执行一次
//重复次数
factoryBean.setRepeatCount(5);
return factoryBean;
}
/**
* 3、创建Scheduler
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean){
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
//关联trigger
factoryBean.setTriggers(simpleTriggerFactoryBean.getObject());
factoryBean.setJobFactory(myadaptableJobFactory);
return factoryBean;
}
}
格式:[秒] [分] [时] [每月的第几日] [月] [每周的第几日] [年]
字段名 | 必须的 | 允许值 | 允许的特殊字符 |
---|---|---|---|
Seconds | YES | 0-59 | , - * / |
Minutes | YES | 0-59 | , - * / |
Hours | YES | 0-23 | , - * / |
Day of month | YES | 1-31 | , - * ? / L W |
Month | YES | 1-12 or JAN-DEC | , - * / |
Day of week | YES | 1-7 or SUN-SAT | , - * ? / L # |
Year | NO | empty, 1970-2099 | , - * / |
注意:有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推
特殊字符说明:
字符 | 含义 |
---|---|
* |
用于 指定字段中的所有值 。比如:* 在分钟中表示 每一分钟 。 |
? |
用于 指定日期中的某一天 ,或是 星期中的某一个星期 。 |
- |
用于 指定范围 。比如:10-12 在小时中表示 10 点,11 点,12 点 。 |
, |
用于 指定额外的值 。比如:MON,WED,FRI 在日期中表示 星期一, 星期三, 星期五 。 |
/ |
用于 指定增量 。比如:0/15 在秒中表示 0 秒, 15 秒, 30 秒, 45 秒 。5/15 在秒中表示 5 秒,20 秒,35 秒,50 秒 。 |
L |
在两个字段中拥有不同的含义。比如:L 在日期(Day of month)表示 某月的最后一天 。在星期(Day of week)只表示 7 或 SAT 。但是,值L 在星期(Day of week)中表示 某月的最后一个星期几 。比如:6L 表示 某月的最后一个星期五 。也可以在日期(Day of month)中指定一个偏移量(从该月的最后一天开始).比如:L-3 表示 某月的倒数第三天 。 |
W |
用于指定工作日(星期一到星期五)比如:15W 在日期中表示 到 15 号的最近一个工作日 。如果第十五号是周六, 那么触发器的触发在 第十四号星期五 。如果第十五号是星期日,触发器的触发在 第十六号周一 。如果第十五是星期二,那么它就会工作开始在 第十五号周二 。然而,如果指定 1W 并且第一号是星期六,那么触发器的触发在第三号周一,因为它不会 “jump” 过一个月的日子的边界。 |
L 和 W |
可以在日期(day-of-month)合使用,表示 月份的最后一个工作日 。 |
# |
用于 指定月份中的第几天 。比如:6#3 表示 月份的第三个星期五 (day 6 = Friday and “#3” = the 3rd one in the month)。其它的有,``2#1表示 月份第一个星期一。 4#5表示 月份第五个星期三。注意: 如果只是指定 #5,则触发器在月份中**不会**触发。 |
注意:字符不区分大小写,MON
和 mon
相同。
cronExpression 示例
表达式 | 含义 |
---|---|
0 0 12 * * ? |
每天中午 12 点 |
0 15 10 ? * * |
每天上午 10 点 15 分 |
0 15 10 * * ? |
每天上午 10 点 15 分 |
0 15 10 * * ? * |
每天上午 10 点 15 分 |
0 15 10 * * ? 2005 |
在 2005 年里的每天上午 10 点 15 分 |
0 * 14 * * ? |
每天下午 2 点到下午 2 点 59 分的每一分钟 |
0 0/5 14 * * ? |
每天下午 2 点到 2 点 55 分每隔 5 分钟 |
0 0/5 14,18 * * ? |
每天下午 2 点到 2 点 55 分, 下午 6 点到 6 点 55 分, 每隔 5 分钟 |
0 0-5 14 * * ? |
每天下午 2 点到 2 点 5 分的每一分钟 |
0 10,44 14 ? 3 WED |
3 月每周三的下午 2 点 10 分和下午 2 点 44 分 |
0 15 10 ? * MON-FRI |
每周一到周五的上午 10 点 15 分 |
0 15 10 15 * ? |
每月 15 号的上午 10 点 15 分 |
0 15 10 L * ? |
每月最后一天的上午 10 点 15 分 |
0 15 10 L-2 * ? |
每月最后两天的上午10点15分 |
0 15 10 ? * 6L |
每月的最后一个星期五的上午 10 点 15 分 |
0 15 10 ? * 6L 2002-2005 |
2002 年到 2005 年每个月的最后一个星期五的上午 10 点 15 分 |
0 15 10 ? * 6#3 |
每月的第三个星期五的上午 10 点 15 分 |
0 0 12 1/5 * ? |
每月的 1 号开始每隔 5 天的中午 12 点 |
0 11 11 11 11 ? |
每年 11 月 11 号上午 11 点 11 分 |
| 3 月每周三的下午 2 点 10 分和下午 2 点 44 分 |
| 0 15 10 ? * MON-FRI
| 每周一到周五的上午 10 点 15 分 |
| 0 15 10 15 * ?
| 每月 15 号的上午 10 点 15 分 |
| 0 15 10 L * ?
| 每月最后一天的上午 10 点 15 分 |
| 0 15 10 L-2 * ?
| 每月最后两天的上午10点15分 |
| 0 15 10 ? * 6L
| 每月的最后一个星期五的上午 10 点 15 分 |
| 0 15 10 ? * 6L 2002-2005
| 2002 年到 2005 年每个月的最后一个星期五的上午 10 点 15 分 |
| 0 15 10 ? * 6#3
| 每月的第三个星期五的上午 10 点 15 分 |
| 0 0 12 1/5 * ?
| 每月的 1 号开始每隔 5 天的中午 12 点 |
| 0 11 11 11 11 ?
| 每年 11 月 11 号上午 11 点 11 分 |