java 定时任务
一、Timer
这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
package com.wh.timingJob; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** * 文章摘自:https://www.jianshu.com/p/b6809b5a0c26 * @Description //Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。 * 使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。 * @Author wanghao * @Date 2019-08-03 10:12 **/ public class TestTimer { public static void main(String[] args) { // 声明任务 TimerTask timerTask = new TimerTask() { @Override public void run() { System.out.println("task run:"+ new Date()); } }; Timer timer = new Timer(); //安排指定的任务在指定的时间开始进行重复的固定延迟执行。这里是每3秒执行一次 /** * @param task task to be scheduled. 执行的任务 * @param delay delay in milliseconds before task is to be executed. 任务执行前的延迟(毫秒)。 * @param period time in milliseconds between successive task executions. 连续任务执行之间的时间(毫秒)。 */ timer.schedule(timerTask,5000,3000); } }
代码如上,有加注释不再赘述。
二、ScheduledExecutorService
也jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
package com.wh.timingJob; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * @Description //ScheduledExecutorService:也jdk自带的一个类;是基于线程池设计的定时任务类, * 每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。 * @Author wanghao * @Date 2019-08-03 10:17 **/ public class TestScheduledExecutorService { public static void main(String[] args) { ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); /** * @param command the task to execute * 命令要执行的任务 * @param initialDelay the time to delay first execution * 初始化延迟第一次执行的延迟时间 * @param period the period between successive executions * 连续执行之间的时间段 * @param unit the time unit of the initialDelay and period parameters * 参数单位初始延迟和周期参数的时间单位 * @return a ScheduledFuture representing pending completion of the task, and whose {@code get()} method will throw an exception upon cancellation * 表示任务的挂起完成 */ service.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("task "+Thread.currentThread().getName()+" ScheduledExecutorService "+new Date()); }; //Time unit representing one second 表示一秒钟的时间单位 },0,3,TimeUnit.SECONDS); // 参数:1、任务体 2、首次执行的延时时间 // 3、任务执行间隔 4、间隔时间单位 //service.scheduleAtFixedRate(()->System.out.println("task ScheduledExecutorService "+new Date()), 0, 3, TimeUnit.SECONDS); } }
代码如上,有加注释不再赘述。
三、Quartz
这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂。
Quartz需要添加依赖
如果SpringBoot版本是2.0.0以后的,则在spring-boot-starter中已经包含了quart的依赖,则可以直接使用spring-boot-starter-quartz依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
如果是1.5.9则要使用以下添加依赖:
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency>
1、单任务Quartz
首先创建一个任务
package com.wh.timingJob.quartz; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; import java.text.SimpleDateFormat; import java.util.Date; /** * @Description //定时任务类 * @Author wanghao * @Date 2019-08-04 21:40 **/ public class TestTask1 extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("TestQuartz01----" + sdf.format(new Date())); } }
然后创建一个启动任务的
package com.wh.timingJob.quartz; import org.quartz.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Description //TODO * @Author wanghao * @Date 2019-08-04 21:41 **/ @Configuration public class QuartzConfig { @Bean public JobDetail testQuartz1() { return JobBuilder.newJob(TestTask1.class).withIdentity("testTask1").storeDurably().build(); } @Bean public Trigger testQuartzTrigger1() { //5秒执行一次 SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(5) .repeatForever(); return TriggerBuilder.newTrigger().forJob(testQuartz1()) .withIdentity("testTask1") .withSchedule(scheduleBuilder) .build(); } }
2、多个任务Quartz
添加一个任务二
package com.wh.timingJob.quartz; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; import java.text.SimpleDateFormat; import java.util.Date; /** * @Description //TODO * @Author wanghao * @Date 2019-08-04 21:40 **/ //Job - 由希望由调度程序执行的组件实现的接口。 public class TestTask2 extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("TestQuartz02----" + sdf.format(new Date())); } }
然后把启动类改为如下;
package com.wh.timingJob.quartz; import org.quartz.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Description //TODO * @Author wanghao * @Date 2019-08-04 21:41 **/ @Configuration public class QuartzConfig { @Bean //JobDetail - 用于定义作业的实例。 public JobDetail testQuartz1() { return JobBuilder.newJob(TestTask1.class).withIdentity("testTask1").storeDurably().build(); } @Bean public Trigger testQuartzTrigger1() { //5秒执行一次 SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(5) .repeatForever(); return TriggerBuilder.newTrigger().forJob(testQuartz1()) .withIdentity("testTask1") .withSchedule(scheduleBuilder) .build(); } @Bean public JobDetail testQuartz2() { return JobBuilder.newJob(TestTask2.class).withIdentity("testTask2").storeDurably().build(); } @Bean public Trigger testQuartzTrigger2() { //cron方式,每隔5秒执行一次 return TriggerBuilder.newTrigger().forJob(testQuartz2()) .withIdentity("testTask2") .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?")) .build(); } }
启动springboot即可。
3、另一种写法
package com.wh.timingJob; /** * @Description //TODO * @Author wanghao * @Date 2019-08-03 10:46 **/ import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; import java.util.Date; /** * jar包依赖 * * <dependency> * <groupId>org.springframework.boot</groupId> * <artifactId>spring-boot-starter-quartz</artifactId> * </dependency> */ public class TestQuartz implements Job { /** * 执行定时任务 * @param jobExecutionContext * @throws JobExecutionException */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("TestQuartz quartz task "+new Date()); } }
package com.wh.timingJob; /** * @Description //TODO * @Author wanghao * @Date 2019-08-03 10:46 **/ import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; import java.util.Date; /** * jar包依赖 * * <dependency> * <groupId>org.springframework.boot</groupId> * <artifactId>spring-boot-starter-quartz</artifactId> * </dependency> */ public class TestQuartz2 implements Job { /** * 执行定时任务 * @param jobExecutionContext * @throws JobExecutionException */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("TestQuartz2222 quartz task "+new Date()); } }
package com.wh.timingJob; import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.stereotype.Component; /** * @Description //TODO * @Author wanghao * @Date 2019-08-03 11:02 **/ @Component public class SchedulerAllJob { @Autowired private SchedulerFactoryBean schedulerFactoryBean; /** * @throws SchedulerException */ public void scheduleJobs() throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); /** * */ scheduleJob1(scheduler); scheduleJob2(scheduler); } /** * 配置Job1 * @param scheduler * @throws SchedulerException */ private void scheduleJob1(Scheduler scheduler) throws SchedulerException{ JobDetail jobDetail = JobBuilder.newJob(TestQuartz.class) .withIdentity("job1", "group1").build(); // 每5s执行一次 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?"); CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") .withSchedule(scheduleBuilder).build(); scheduler.scheduleJob(jobDetail,cronTrigger); } /** * 配置Job * @param scheduler * @throws SchedulerException */ private void scheduleJob2(Scheduler scheduler) throws SchedulerException{ JobDetail jobDetail = JobBuilder.newJob(TestQuartz2.class) .withIdentity("job2", "group1").build(); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?"); // 每10s执行一次 CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger2", "group1") .withSchedule(scheduleBuilder).build(); scheduler.scheduleJob(jobDetail,cronTrigger); } }
package com.wh.timingJob; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; /** * @Description //TODO * @Author wanghao * @Date 2019-08-03 10:49 **/ @Component public class InitRunner implements CommandLineRunner { @Autowired SchedulerAllJob schedulerAllJob; @Override public void run(String... args) throws Exception { schedulerAllJob.scheduleJobs(); } }
TestQuartz都是任务的实现
SchedulerAllJob 任务调度。
InitRunner 任务启动。
注:在使用SpringBoot构建项目时,我们通常有一些预先数据的加载。那么SpringBoot提供了一个简单的方式来实现–CommandLineRunner。换句话说就是,项目启动后就执行的
详情可点击链接:https://www.cnblogs.com/myblogs-miller/p/9046425.html https://blog.csdn.net/qq_34531925/article/details/82527066
四、使用Spring Task
package com.wh.timingJob; /** * @Description // Spring Task:Spring3.0以后自带的task, * 可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。 * @Author wanghao * @Date 2019-08-03 10:24 **/ import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.Date; /** * 需要引入jar包依赖: * <dependencies> * <dependency> * <groupId>org.springframework.boot</groupId> * <artifactId>spring-boot-starter-web</artifactId> * </dependency> * <dependency> * <groupId>org.springframework.boot</groupId> * <artifactId>spring-boot-starter</artifactId> * </dependency> * <dependency> * <groupId>org.projectlombok</groupId> * <artifactId>lombok</artifactId> * <optional>true</optional> * </dependency> * <dependency> * <groupId>org.springframework.boot</groupId> * <artifactId>spring-boot-starter-test</artifactId> * <scope>test</scope> * </dependency> * </dependencies> */ /** * 例子: * # 每月的最后1天 * @Scheduled(cron = "0 0 18 28–31 * ?") * public void doAtLastDayOfMonth() { * final Calendar calendar = Calendar.getInstance(); * if (c.get(Calendar.DATE) == c.getActualMaximum(Calendar.DATE)) { * // do something here... * } * } * * 说明: * Java(Spring) * * * * * * * * springboot不支持年 * - - - - - - - * | | | | | | | * | | | | | | + year [optional] * | | | | | +----- day of week (0 - 7) (Sunday=0 or 7) * | | | | +---------- month (1 - 12) * | | | +--------------- day of month (1 - 31) * | | +-------------------- hour (0 - 23) * | +------------------------- min (0 - 59) * +------------------------------ second (0 - 59) */ @Component @EnableScheduling public class AlarmTask { /**默认是fixedDelay 上一次执行完毕时间后执行下一轮 springboot不支持年*/ @Scheduled(cron = "0/5 * * * * *") public void run() throws InterruptedException { System.out.println(Thread.currentThread().getName()+"=====>>>>>使用cron {}"+new Date()); Thread.sleep(6000); System.out.println(Thread.currentThread().getName()+"=====>>>>>使用cron sleep 6 {}"+new Date()); } /**fixedRate:间隔5s执行一次*/ @Scheduled(fixedRate = 5000) public void run1() throws InterruptedException { System.out.println(Thread.currentThread().getName()+"=====>>>>> 使用fixedRate {}"+new Date()); } /**fixedDelay:上一次执行完毕时间点之后5秒再执行*/ @Scheduled(fixedDelay = 5000) public void run2() throws InterruptedException { System.out.println(Thread.currentThread().getName()+"=====>>>>> 使用fixedDelay {}"+new Date()); } /**第一次延迟2秒后执行,之后按fixedDelay的规则每5秒执行一次*/ // @Scheduled(initialDelay = 2000, fixedDelay = 5000) public void run3(){ System.out.println(Thread.currentThread().getName()+"=====>>>>> 使用initialDelay {}"+new Date()); } }
这次写的都只是快速上手启动的模板,后期会贴上任务的详情介绍链接。
cron
cron表达式 每隔指定时间执行任务,
例如:每个3秒执行,第一次01执行任务,任务执行4秒,第二次任务执行的时候判断任务仍然在执行则跳过,第三次执行任务的时候检查任务已经结束,开始执行任务,01+3+3>01+4所以是07开始下一次任务,如下图所示,定时任务轮询如果任务正在执行则跳过这次,如果检测任务没有运行则正常执行。

fixeddelay
上一次任务执行结束等待间隔时间执行,这个很好理解,例如:间隔时间是3秒,01开始任务,任务执行4秒,下次任务执行时间就是01+4+3=08;
fixedrate
间隔时间执行,如果任务时间超出间隔时间,则下次任务再这次任务结束立即执行。例如:间隔时间是3秒,01开始任务,任务执行4秒,下次任务执行时间就是01+4=05;立即执行
@Scheduled(cron ="${testCron2}")
public void testCron2() {
log.info("开始 testCron2 ---------");
}
@Scheduled(cron ="0/1 * * * * ? ")
public void testCron() {
log.info("开始 testCron ---------");
}
@Scheduled(fixedRate = 3000)
public void testFixedRate() throws InterruptedException {
log.info("开始 testFixedRate ---------");
Thread.sleep(14000);
}
@Scheduled(fixedDelay = 3000)
public void testFixedDelay() throws InterruptedException {
log.info("开始 testFixedDelay ---------");
Thread.sleep(4000);
}
/**
* fixedDelayString 可以从配置文件获取
*/
@Scheduled(fixedDelayString = "${fixedDelayString}")
public void TestFixedDelayString() {
log.info("开始 TestFixedDelayString ---------");
}
/**
* fixedRateString 可以从配置文件获取
*/
@Scheduled(fixedRateString = "${fixedRateString}")
public void TestFixedRateString() {
log.info("开始 TestFixedRateString ---------");
}
配置文件
fixedDelayString: 4000 fixedRateString: 4000 testCron2: 0/1 * * * * ?
参考资料:

浙公网安备 33010602011771号