定时任务的实现方式
- Timer:Java自带的java.util.Time类,这个类允许你调度一个java.util.TimerTask任务。这种方式让程序按照某个频度执行,但不能在指定时间执行。一般使用较少。
- SheduledExecutorService:jdk自带的类,是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
- Spring Task:Spring3.0以后自带的task,相当于一个轻量级的Quartz。
- Quartz:调度器可以让程序在指定的时间执行,也可以按照某个频度执行,配置起来稍显复杂。
本文只分析后两个。
一、Spring Task
在SpringBoot项目中,我们可以很优雅的使用注解来实现定时任务,首先创建项目,添加starter-web依赖(默认包含了定时任务依赖),创建定时任务类,在启动类上使用@EnableScheduling注解开启对定时任务的支持即可。
代码示例:
@Component
public class SheduleService {
// 每5秒
@Scheduled(cron = "0/5 * * * * *")
public void scheduled() {
System.out.println("=====>>>>>使用cron " + System.currentTimeMillis());
}
@Scheduled(fixedRate = 5000)
public void scheduled1() {
System.out.println("=====>>>>>使用fixedRate " + System.currentTimeMillis());
}
@Scheduled(fixedDelay = 5000)
public void scheduled2() {
System.out.println("=====>>>>>fixedDelay " + System.currentTimeMillis());
}
}
@SpringBootApplication
@EnableScheduling
public class SpringbootSheduleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSheduleApplication.class, args);
}
}
结果:
=====>>>>>使用cron 1600760665001
=====>>>>>使用fixedRate 1600760668808
=====>>>>>fixedDelay 1600760668808
多线程执行
在SpringBoot项目中一般使用config配置类的方式添加配置,所以新建一个AsyncConfig类
然后在定时任务的类或者方法上添加@Async 。最后重启项目,每一个任务都是在不同的线程中。
corn表达式在此不去介绍。
结果:
=====>>>>>使用fixedRate 1600761599395taskExecutor-1
=====>>>>>fixedDelay 1600761599395taskExecutor-2
=====>>>>>使用cron 1600761600001taskExecutor-3
=====>>>>>使用fixedRate 1600761604391taskExecutor-4
=====>>>>>fixedDelay 1600761604393taskExecutor-5
=====>>>>>使用cron 1600761605002taskExecutor-6
=====>>>>>使用fixedRate 1600761609391taskExecutor-7
=====>>>>>fixedDelay 1600761609394taskExecutor-8
=====>>>>>使用cron 1600761610000taskExecutor-9
=====>>>>>使用fixedRate 1600761614390taskExecutor-10
=====>>>>>fixedDelay 1600761614395taskExecutor-1
=====>>>>>使用cron 1600761615001taskExecutor-2
二、Quartz
如果SpringBoot版本是2.0.0以后的,添加依赖spring-boot-starter-quartz即可。创建任务类QuartzService,继承QuartzJobBean
代码示例:
public class QuartzService extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("quartz task" + new Date());
}
}
@Configuration
public class QuartzConfig {
@Bean
public JobDetail quartzDetail() {
return JobBuilder.newJob(QuartzService.class).withIdentity("quartzService").storeDurably().build();
}
@Bean
public Trigger quartzTrigger() {
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10) //设置时间周期单位秒
.repeatForever();
return TriggerBuilder.newTrigger().forJob(quartzDetail())
.withIdentity("quartzService")
.withSchedule(scheduleBuilder)
.build();
}
}
启动服务即可
结果:
quartz taskTue Sep 22 16:16:26 CST 2020
quartz taskTue Sep 22 16:16:36 CST 2020
quartz taskTue Sep 22 16:16:46 CST 2020
更复杂的定时任务:系统启动时获取任务信息开启定时任务,访问修改定时任务时间重启定时任务
代码示例:
public class MyJob implements Job {
private final static Logger log = LoggerFactory.getLogger(MyJob.class);
//@Autowired
//private MyService myService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info("任务开始执行了");
try {
executeTask();
} catch (SchedulerException e) {
e.printStackTrace();
}
log.info("任务执行结束了");
}
private void executeTask() throws SchedulerException {
//myService.bizFunction();
System.out.println("quartz定时任务执行内容");
}
}
@Configuration
public class QuartzJobListener implements ApplicationListener<ContextRefreshedEvent> {
private final static Logger log = LoggerFactory.getLogger(QuartzJobListener.class);
@Autowired
private QuartzManager quartzManager;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
try {
// 开启一个指定的定时任务;需要设计从数据库获取定时任务对象列表,循环列表开启每个定时任务
quartzManager.startJob();
log.info("任务已经启动......");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 初始注入scheduler
*/
@Bean
public Scheduler scheduler() throws SchedulerException{
SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
return schedulerFactoryBean.getScheduler();
}
}
@Configuration
public class QuartzManager {
public static final String JOB1="job1";
public static final String GROUP1="group1";
/**默认每个星期凌晨一点执行*/
//public static final String DEFAULT_CRON="0 0 1 ? * L";
/**默认5秒执行一次*/
public static final String DEFAULT_CRON="*/5 * * * * ?";
/**
* 任务调度
*/
@Autowired
private Scheduler scheduler;
/**
* 开始执行定时任务
*/
public void startJob() throws SchedulerException {
startJobTask(scheduler);
scheduler.start();
}
/**
* 开始执行所有的定时任务
*/
public void startAllJob(List<String> list) throws SchedulerException, ClassNotFoundException {
startAllJobTask(scheduler,list);
scheduler.start();
}
/**
* 启动定时任务
* @param scheduler
*/
private void startJobTask(Scheduler scheduler) throws SchedulerException {
JobDetail jobDetail= JobBuilder.newJob(MyJob.class).withIdentity(JOB1,GROUP1).build();
CronScheduleBuilder cronScheduleBuilder=CronScheduleBuilder.cronSchedule(DEFAULT_CRON);
CronTrigger cronTrigger=TriggerBuilder.newTrigger().withIdentity(JOB1,GROUP1).withSchedule(cronScheduleBuilder).build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
/**
* 启动所有的定时任务
* @param scheduler
*/
private void startAllJobTask(Scheduler scheduler,List<String> list) throws SchedulerException, ClassNotFoundException {
Class clazz = Class.forName(list.get(0));
JobDetail jobDetail= JobBuilder.newJob(clazz).withIdentity(list.get(1),list.get(2)).build();
CronScheduleBuilder cronScheduleBuilder=CronScheduleBuilder.cronSchedule(list.get(3));
CronTrigger cronTrigger=TriggerBuilder.newTrigger().withIdentity(JOB1,GROUP1).withSchedule(cronScheduleBuilder).build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
/**
* 获取Job信息
* @param name
* @param group
*/
public String getjobInfo(String name,String group) throws SchedulerException {
TriggerKey triggerKey=new TriggerKey(name,group);
CronTrigger cronTrigger= (CronTrigger) scheduler.getTrigger(triggerKey);
return String.format("time:%s,state:%s",cronTrigger.getCronExpression(),
scheduler.getTriggerState(triggerKey).name());
}
/**
* 修改任务的执行时间
* @param name
* @param group
* @param cron cron表达式
* @return
* @throws SchedulerException
*/
public boolean modifyJob(String name,String group,String cron) throws SchedulerException{
Date date=null;
TriggerKey triggerKey=new TriggerKey(name, group);
CronTrigger cronTrigger= (CronTrigger) scheduler.getTrigger(triggerKey);
String oldTime=cronTrigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)){
CronScheduleBuilder cronScheduleBuilder=CronScheduleBuilder.cronSchedule(cron);
CronTrigger trigger=TriggerBuilder.newTrigger().withIdentity(name,group)
.withSchedule(cronScheduleBuilder).build();
date=scheduler.rescheduleJob(triggerKey,trigger);
}
return date != null;
}
/**
* 暂停所有任务
* @throws SchedulerException
*/
public void pauseAllJob()throws SchedulerException{
scheduler.pauseAll();
}
/**
* 暂停某个任务
* @param name
* @param group
* @throws SchedulerException
*/
public void pauseJob(String name,String group)throws SchedulerException{
JobKey jobKey=new JobKey(name,group);
JobDetail jobDetail=scheduler.getJobDetail(jobKey);
if (jobDetail==null)
return;
scheduler.pauseJob(jobKey);
}
/**
* 恢复所有任务
* @throws SchedulerException
*/
public void resumeAllJob()throws SchedulerException{
scheduler.resumeAll();
}
/**
* 恢复某个任务
*/
public void resumeJob(String name,String group)throws SchedulerException{
JobKey jobKey=new JobKey(name,group);
JobDetail jobDetail=scheduler.getJobDetail(jobKey);
if (jobDetail==null)
return;
scheduler.resumeJob(jobKey);
}
/**
* 删除某个任务
* @param name
* @param group
* @throws SchedulerException
*/
public void deleteJob(String name,String group)throws SchedulerException {
JobKey jobKey=new JobKey(name, group);
JobDetail jobDetail=scheduler.getJobDetail(jobKey);
if (jobDetail==null)
return;
scheduler.deleteJob(jobKey);
}
}
@RestController
public class CronController {
@Autowired
private QuartzManager quartzManager;
@GetMapping("modify")
public String modify() throws SchedulerException {
/**10秒执行一次*/
String cron="*/10 * * * * ?";
quartzManager.pauseJob(QuartzManager.JOB1,QuartzManager.GROUP1);
quartzManager.modifyJob(QuartzManager.JOB1,QuartzManager.GROUP1,cron);
return "ok";
}
}
结果:
2020-09-22 17:26:05.001 INFO 7748 — [eduler_Worker-2] com.ldc.springboot_shedule.quartz.MyJob : 任务执行结束了
2020-09-22 17:26:10.001 INFO 7748 — [eduler_Worker-3] com.ldc.springboot_shedule.quartz.MyJob : 任务开始执行了
变更为
2020-09-22 17:31:10.001 INFO 7748 — [duler_Worker-10] com.ldc.springboot_shedule.quartz.MyJob : 任务执行结束了
2020-09-22 17:31:20.001 INFO 7748 — [eduler_Worker-1] com.ldc.springboot_shedule.quartz.MyJob : 任务开始执行了