网站建设公司怎么宣传,受欢迎的大连网站建设,手机和网站页面模板,制作网站品牌公司文章目录 【README】【1】Quartz任务调度框架【1.1】Job调度任务【1.2】任务调度触发器Trigger【1.3】\*Quartz框架执行调度任务代码实践【1.3.1】硬编码执行Quartz调度任务【1.3.2】基于生产者模式执行quartz调度任务#xff08;推荐#xff09; 【2】spring集成Quartz【2.1… 文章目录 【README】【1】Quartz任务调度框架【1.1】Job调度任务【1.2】任务调度触发器Trigger【1.3】\*Quartz框架执行调度任务代码实践【1.3.1】硬编码执行Quartz调度任务【1.3.2】基于生产者模式执行quartz调度任务推荐 【2】spring集成Quartz【2.1】spring管理quartz组件对象【2.1.1】spring管理quartz的Job【2.1.2】spring管理quartz的JobDetail【2.1.3】spring管理quartz的Trigger【2.1.4】spirng管理quartz的Scheduler 【2.2】spring启动quartz调度器执行调度任务 【3】JDK Timer定时器【3.1】JDK Timer基础知识回顾【3.2】定时器任务单次执行【3.2.1】给定延迟时间之后执行单次任务【3.2.2】在给定时间点执行单次任务 【3.3】 定时器任务重复执行【3.3.1】在给定延迟时间后重复执行【3.2.2】在给定时间点重复执行【3.3.3】定时器任务重复执行注意点 【3.4】取消调度器与调度任务【3.4.1】 在run方法里取消调度任务 【3.5】定时器Timer与调度线程池对比【3.5.1】调度线程池执行调度任务回顾【3.5.2】定时器与调度线程池ScheduledExecutorService对比 【README】
本文部分内容总结自《spring揭秘》作者王福强非常棒的一本书墙裂推荐
本文部分内容总结自 https://juejin.cn/post/7158071449314394119
本文代码参见 github-springDiscover-chapter31 【1】Quartz任务调度框架
1Quartz是一款开源的任务调度框架 官网介绍参见 quartz-scheduler
官网介绍总结翻译 quartz是一款功能丰富的开源作业调度库可以集成几乎任何java应用从最小的单体应用到最大的电子商务系统。 quartz能够用于创建简单或复杂的调度以执行数十数百数万个作业这些作业的任务可以被定义为标准的java组件可以执行你编程让它们做的任何操作。quartz调度器包含许多企业级功能如支持JTA事务与集群。应用场景 定时执行业务逻辑如数据同步发送短信每隔一段时间执行业务逻辑如每隔5秒发送1次心跳
2相对于JDK的Timer之类的简单任务调度程序来说Quartz拥有丰富的功能如下
允许批处理任务状态的持久化批处理任务的远程调度基于web的监控接口集群支持 同一时刻只有一个任务执行当一个任务宕机之后其它服务会接管这个任务插件式的可扩展性
3Quartz组件清单
Job 抽象调度任务作业JobDetail封装job的详细信息如job名称组名称job的classJobDataMap等Trigger触发器抽象job触发规则如执行开始时间结束时间执行频率Scheduler调度器 使用Trigger定义的规则执行jobJobBuilderJob生成器用于创建Job实例TriggerBuilderTrigger生成器用于创建Trigger实例JobExecutionContextJob运行时上下文JobDataMap 封装参数键值对用于Job与JobDetail的数据交互
4Quartz基本组件关系如下 5使用 quartz任务调度框架需要引入对应maven依赖如下
dependencygroupIdorg.quartz-scheduler/groupIdartifactIdquartz/artifactIdversion2.3.2/version
/dependency【1.1】Job调度任务
1quartz中调度任务job定义
public interface Job {void execute(JobExecutionContext var1) throws JobExecutionException;
}2调度任务实现job接口
public class TomScheduleJob implements Job {Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {// do sth.System.out.println(MyScheduleJob#当前时间 BusiDatetimeUtils.getNowText());}
}【1.2】任务调度触发器Trigger
1触发器定义job触发规则如每隔10分钟执行1次每天早上7点9点准时执行1次
2触发器Trigger定义如下
public interface Trigger extends Serializable, Cloneable, ComparableTrigger {long serialVersionUID -3904243490805975570L;int MISFIRE_INSTRUCTION_SMART_POLICY 0;int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY -1;int DEFAULT_PRIORITY 5;TriggerKey getKey();JobKey getJobKey();String getDescription();String getCalendarName();JobDataMap getJobDataMap();int getPriority();boolean mayFireAgain();Date getStartTime();Date getEndTime();Date getNextFireTime();Date getPreviousFireTime();Date getFireTimeAfter(Date var1);Date getFinalFireTime();int getMisfireInstruction();TriggerBuilder? extends Trigger getTriggerBuilder();ScheduleBuilder? extends Trigger getScheduleBuilder();boolean equals(Object var1);int compareTo(Trigger var1);
// ...
}2触发器的两种主要实现
SimpleTrigger指定基于时间间隔的调度规则触发规则CronTrigger指定基于cron表达式的调度规则包括但不限于时间间隔还可以指定具体时间执行触发规则更加灵活 【1.3】*Quartz框架执行调度任务代码实践
【1.3.1】硬编码执行Quartz调度任务
【TomQuartzJob】
public class TomQuartzJob implements Job {Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {// do sth.System.out.println(TomQuartzJob#当前时间 BusiDatetimeUtils.getNowText());}
}【TomQuartzJobMain】
public class TomQuartzJobMain {public static void main(String[] args) throws Exception {executeScheduleJob();}private static void executeScheduleJob() throws ParseException, SchedulerException {// 新建触发器SimpleTriggerImpl simpleTrigger new SimpleTriggerImpl(tomSimpleTrigger, tomSimpleTriggerGroup, new Date(), null, SimpleTriggerImpl.REPEAT_INDEFINITELY, 5000); // 每隔5秒执行1次CronTriggerImpl cronTrigger new CronTriggerImpl(tomSimpleTrigger, tomSimpleTriggerGroup, */5 * * * * ?);// 新建调度器Scheduler scheduler new StdSchedulerFactory().getScheduler();scheduler.start();// 新建调度任务详情JobDetailImpl tomJobDetail new JobDetailImpl(tomJobDetail, TomQuartzJob.class);// 新增调度任务这里是新增并没有执行执行由触发器来负责
// scheduler.scheduleJob(tomJobDetail, simpleTrigger);scheduler.scheduleJob(tomJobDetail, cronTrigger);}
}【1.3.2】基于生产者模式执行quartz调度任务推荐
1基于生成器模式执行调度任务 参考 quick-start
【TomTimeRemindJob】
public class TomTimeRemindJob implements Job {Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.out.println();context.getMergedJobDataMap().forEach((k,v)- System.out.println(k v));context.getJobDetail().getJobDataMap().forEach((k,v)- System.out.println(k v));System.out.println(TomTimeRemindJob now BusiDatetimeUtils.getNowText());}
}【TomTimeRemindJobMain】
public class TomTimeRemindJobMain {public static void main(String[] args) throws SchedulerException {// 创建调度器实例Scheduler scheduler StdSchedulerFactory.getDefaultScheduler();// 开启调度器scheduler.start();// 执行调度作业executeScheduleJob(scheduler);// 关闭调度器
// scheduler.shutdown();}private static void executeScheduleJob(Scheduler scheduler) throws SchedulerException {// 创建JobDetail并与TomTimeRemindJob 绑定JobDetail jobDetail JobBuilder.newJob(TomTimeRemindJob.class).withIdentity(tomJob01, tomJob01Group).build();// 立即触发作业执行每5秒重复一次Trigger simpleTrigger TriggerBuilder.newTrigger().withIdentity(tomTrigger01, tomTrigger01Group).startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();// 告诉quartz使用我们的触发器调度作业scheduler.scheduleJob(jobDetail, simpleTrigger);}
}【2】spring集成Quartz
1通过上述代码【TomTimeRemindJobMain】 本文发现使用Quartz框架执行调度任务需要依赖以下4个组件Job JobDetail Trigger Scheduler Job调度任务 JobDetail 用于封装job详细信息 Trigger触发器定义触发规则 Scheduler调度器根据触发器的规则执行调度任务作业
2可以想到spring集成Quartz的底层原理 把JobJobDetail SimpleTrigger Scheduler对象创建与依赖关系装配由spring来完成无需客户端实现 spring采用工厂方法FactoryBean来管理quartz调度任务所需组件
3spring集成Quartz需要新增maven依赖如下
dependencygroupIdorg.springframework/groupIdartifactIdspring-context-support/artifactIdversion6.1.10/version/dependency【2.1】spring管理quartz组件对象
1本章节部分内容总结自 spring-quartz-schedule 【2.1.1】spring管理quartz的Job
1spring提供了QuartzJobBean用于抽象调度任务自定义调度任务需要继承QuartzJobBean并重写executeInternal()方法
2QuartzJobBean定义注意quartz的JobDetail封装了Job的class对象由JobDetail实例化job所以spring无需注册job
public abstract class QuartzJobBean implements Job {public QuartzJobBean() {}public final void execute(JobExecutionContext context) throws JobExecutionException {try {BeanWrapper bw PropertyAccessorFactory.forBeanPropertyAccess(this);MutablePropertyValues pvs new MutablePropertyValues();pvs.addPropertyValues(context.getScheduler().getContext());pvs.addPropertyValues(context.getMergedJobDataMap());bw.setPropertyValues(pvs, true);} catch (SchedulerException var4) {throw new JobExecutionException(var4);}this.executeInternal(context);}protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException;
}【自定义job继承QuartzJobBean】TomSpringQuartzJobBean
public class TomSpringQuartzJobBean extends QuartzJobBean {Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {System.out.println(TomSpringQuartzJobBean #当前时间 BusiDatetimeUtils.getNowText());}
}【2.1.2】spring管理quartz的JobDetail
1在quartz中 job抽象了调度任务而job的上下文信息由JobDetail封装Job与JobDetail的数据交互通过JobDataMap实现
2spring注册JobDetail有两种方式
方式1 JobDetailFactoryBean 注册JobDetail 推荐 方式2 通过 MethodInvokingJobDetailFactoryBean 注册JobDetail 本文不介绍
【springquartz.xml】 JobDetailFactoryBean 注册JobDetail
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!-- 通过 JobDetailFactoryBean 注册JobDetail --bean classorg.springframework.scheduling.quartz.JobDetailFactoryBeanproperty namename valuetomJob /property namegroup valuetomJobGroup /property namejobClass valuecom.tom.springnote.chapter31schedule.springquartz.SpringScheduleJob /property namedurability valuetrue /property namedescription valuetomJobDetail /property namejobDataMapmapentry keymessage valuehello world /entry keycity valuechengdu //map/property/bean
/beans【2.1.3】spring管理quartz的Trigger
1trigger触发器定义了执行调度任务的规则 如每5秒执行1次
2spring也是通过FactoryBean注册Trigger
SimpleTriggerFactoryBean 简单触发器CronTriggerFactoryBean 带有cron表达式的触发器
【springquartz.xml】 SimpleTriggerFactoryBean 注册Trigger
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!-- 通过 JobDetailFactoryBean 注册JobDetail --bean idtomJobDetail classorg.springframework.scheduling.quartz.JobDetailFactoryBeanproperty namename valuetomJob /property namegroup valuetomJobGroup /property namejobClass valuecom.tom.springnote.chapter31schedule.springquartz.SpringScheduleJob /property namedurability valuetrue /property namedescription valuetomJobDetail /property namejobDataMapmapentry keymessage valuehello world /entry keycity valuechengdu //map/property/bean!-- 通过 SimpleTriggerFactoryBean 注册触发器 --bean classorg.springframework.scheduling.quartz.SimpleTriggerFactoryBeanproperty namename valuetomTrigger /property namegroup valuetomTriggerGroup /property namejobDetail reftomJobDetail /property namerepeatInterval value5000 / !-- 单位毫秒每5秒执行1次--property namerepeatCount value-1 / !-- -1表示永远重复 --/bean!-- 通过 CronTriggerFactoryBean 注册触发器 --bean classorg.springframework.scheduling.quartz.CronTriggerFactoryBeanproperty namename valuetomCronTrigger /property namegroup valuetomCronTriggerGroup /property namejobDetail reftomJobDetail /property namecronExpression ref*/3 * * * * ? / !-- 每3秒执行1次--/bean/beans3补充 多个trigger定义的规则可以同时作用于同一个JobDetail 或Job 本文认为多个Trigger规则的组合太过复杂1个trigger对应1个Job足够满足日常业务需求本文不再深入研究多个trigger组合的情况有兴趣的同学自行研究 【2.1.4】spirng管理quartz的Scheduler
1scheduler调度器使用触发器Trigger定义的规则执行调度任务job
2spring通过SchedulerFactoryBean注册scheduler
【springquartz.xml】 SchedulerFactoryBean注册scheduler
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!-- 通过 JobDetailFactoryBean 注册JobDetail --bean idtomJobDetail classorg.springframework.scheduling.quartz.JobDetailFactoryBeanproperty namename valuetomJob /property namegroup valuetomJobGroup /property namejobClass valuecom.tom.springnote.chapter31schedule.springquartz.TomSpringQuartzJobBean /property namedurability valuetrue /property namedescription valuetomJobDetail /property namejobDataMapmapentry keymessage valuehello world /entry keycity valuechengdu //map/property/bean!-- 通过 SimpleTriggerFactoryBean 注册触发器 --bean idtomSimpleTrigger classorg.springframework.scheduling.quartz.SimpleTriggerFactoryBeanproperty namename valuetomTrigger /property namegroup valuetomTriggerGroup /property namejobDetail reftomJobDetail /property namerepeatInterval value5000 / !-- 单位毫秒每5秒执行1次--property namerepeatCount value-1 / !-- -1表示永远重复 --/bean!-- 通过 CronTriggerFactoryBean 注册触发器 --bean idtomCronTrigger classorg.springframework.scheduling.quartz.CronTriggerFactoryBeanproperty namename valuetomCronTrigger /property namegroup valuetomCronTriggerGroup /property namejobDetail reftomJobDetail /property namecronExpression ref*/3 * * * * ? / !-- 每3秒执行1次--/bean!-- 通过SchedulerFactoryBean注册scheduler --bean classorg.springframework.scheduling.quartz.SchedulerFactoryBeanproperty nametriggers !-- 可以装配多个触发器当然日常开发1个足够 --listref beantomSimpleTrigger /ref beantomCronTrigger //list/property/bean
/beans【2.2】spring启动quartz调度器执行调度任务
1spring容器ApplicationContext启动时SchedulerFactoryBean所管理的调度器Scheduler跟着自动启动且Scheduler随着ApplicationContext的关闭而自动关闭
当调度任务的所有对象实例注册到ioc容器后ApplicationContext启动时Scheduler也启动Scheduler立即开始执行调度任务
【TomSpringQuartzJobBeanMain】
public class TomSpringQuartzJobBeanMain {public static void main(String[] args) {ClassPathXmlApplicationContext springContext new ClassPathXmlApplicationContext(chapter31schedule/springquartz.xml);((AbstractApplicationContext) springContext).registerShutdownHook();}
}【执行效果】 2个调度任务在执行因为有2个触发器tomSimpleTrigger-每5秒执行1次tomCronTrigger-每3秒执行1次
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:23.623
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:24.002
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:27.000
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:28.505
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:30.000
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:33.010
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:33.501
TomSpringQuartzJobBean #当前时间2024-10-13 21:42:36.003【3】JDK Timer定时器
【3.1】JDK Timer基础知识回顾
1Timer定时器组件
TimerTask抽象调度任务Timer抽象调度器用于定义任务触发规则并执行调度任务 类似于肩负了quartz的Scheduler与Trigger职责 只能配置简单规则不能配置cron表达式
2Timer使用TimerTask抽象调度任务自定义调度任务需要继承TimerTask
由代码可知 TimerTask本质上是Runnable即可以提交给线程的任务
public abstract class TimerTask implements Runnable {// ...
}3部分代码总结自 java-timer-and-timertask 【3.2】定时器任务单次执行
【3.2.1】给定延迟时间之后执行单次任务
1在当前时间等待给定延迟时间之后执行调度任务
【OnceTimerTaskExecuteAfterDelayMain】给定延迟时间之后仅执行1次调度任务
public class OnceTimerTaskExecuteAfterDelayMain {public static void main(String[] args) {TimerTask timerTask new TimerTask() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());}};// 通过jdk 定时器执行调度任务Timer timer new Timer();System.out.println(当前时间 BusiDatetimeUtils.getNowText());// 在给定延迟时间(5s)之后执行调度任务仅执行1次timer.schedule(timerTask, 5000);System.out.println(after timer.schedule()新增调度任务之后);try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}// 取消调度器执行(主线程结束)timer.cancel();System.out.println(主线程结束 当前时间 BusiDatetimeUtils.getNowText());}
} public void schedule(TimerTask task, long delay) { if (delay 0)throw new IllegalArgumentException(Negative delay.);sched(task, System.currentTimeMillis()delay, 0); // period0 表示当前任务仅执行1次 }
private void sched(TimerTask task, long time, long period) { // ...
}【解说】period参数表示2个相邻任务执行的时间间隔单位毫秒
若为0表示仅执行1次 若为整数表示时间间隔
【执行效果】
当前时间2024-10-16 20:51:52.281
after timer.schedule()新增调度任务之后
线程id15 当前时间2024-10-16 20:51:57.298
主线程结束 当前时间2024-10-16 20:51:57.298【3.2.2】在给定时间点执行单次任务
1在给定时间点执行调度任务
【OnceTimerTaskExecuteAtGivenTime】 在给定时间点执行调度任务仅执行1次
public class OnceTimerTaskExecuteAtGivenTime {public static void main(String[] args) {TimerTask timerTask new TimerTask() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());}};// 通过jdk 定时器执行调度任务Timer timer new Timer();System.out.println(当前时间 BusiDatetimeUtils.getNowText());// 在给定时间点当前时间加5秒的时间执行调度任务仅执行1次timer.schedule(timerTask, BusiDatetimeUtils.timeAfterSecond(5));System.out.println(after timer.schedule()新增调度任务之后);try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}// 取消调度器执行(主线程结束)timer.cancel();System.out.println(主线程结束 当前时间 BusiDatetimeUtils.getNowText());}
}
public void schedule(TimerTask task, Date time) {sched(task, time.getTime(), 0); // period0 表示仅执行1次 }【执行效果】
当前时间2024-10-16 20:55:09.981
after timer.schedule()新增调度任务之后
线程id15 当前时间2024-10-16 20:55:14.984
主线程结束 当前时间2024-10-16 20:55:14.986【3.3】 定时器任务重复执行
【3.3.1】在给定延迟时间后重复执行
1使用Timer定时器在给定延迟时间后重复执行调度任务
【RepeatableTimerTaskExecuteAfterDelayMain】
public class RepeatableTimerTaskExecuteAfterDelayMain {public static void main(String[] args) {TimerTask timerTask new TimerTask() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());}};// 通过jdk 定时器执行调度任务Timer timer new Timer();System.out.println(当前时间 BusiDatetimeUtils.getNowText());// 在给定延迟时间(5s)之后执行调度任务间隔2秒重复执行timer.schedule(timerTask, 5000, 2000);System.out.println(after timer.schedule()新增调度任务之后);try {TimeUnit.SECONDS.sleep(10); // 睡眠10s后关闭定时器以便调度任务可以重复执行} catch (InterruptedException e) {throw new RuntimeException(e);}// 取消调度器执行(主线程结束)timer.cancel();System.out.println(主线程结束 当前时间 BusiDatetimeUtils.getNowText());}
}【执行效果】
当前时间2024-10-16 21:01:49.933
after timer.schedule()新增调度任务之后
线程id15 当前时间2024-10-16 21:01:54.950
线程id15 当前时间2024-10-16 21:01:56.951
线程id15 当前时间2024-10-16 21:01:58.957
主线程结束 当前时间2024-10-16 21:01:59.946【3.2.2】在给定时间点重复执行
【RepeatableTimerTaskExecuteAtGivenTime】
public class RepeatableTimerTaskExecuteAtGivenTime {public static void main(String[] args) {TimerTask timerTask new TimerTask() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());}};// 通过jdk 定时器执行调度任务Timer timer new Timer();System.out.println(当前时间 BusiDatetimeUtils.getNowText());// 在给定时间点当前时间加5秒的时间执行调度任务间隔2s重复执行timer.schedule(timerTask, BusiDatetimeUtils.timeAfterSecond(5), 2000);System.out.println(after timer.schedule()新增调度任务之后);try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}// 取消调度器执行(主线程结束)timer.cancel();System.out.println(主线程结束 当前时间 BusiDatetimeUtils.getNowText());}
}【执行效果】
当前时间2024-10-16 21:07:12.258
after timer.schedule()新增调度任务之后
线程id15 当前时间2024-10-16 21:07:17.260
线程id15 当前时间2024-10-16 21:07:19.261
线程id15 当前时间2024-10-16 21:07:21.275
主线程结束 当前时间2024-10-16 21:07:22.261【3.3.3】定时器任务重复执行注意点
1 若一个任务执行耗时大于调度间隔或周期period则会延迟整个执行链无论是在延迟时间后还是给定时间点执行
【RepeatableTimerTaskDelayWholeChainAtGivenTime】
public class RepeatableTimerTaskDelayWholeChainAtGivenTime {public static void main(String[] args) {TimerTask timerTask new TimerTask() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());try {TimeUnit.SECONDS.sleep(5); // 模拟单个任务执行耗时5秒} catch (InterruptedException e) {throw new RuntimeException(e);}}};// 通过jdk 定时器执行调度任务Timer timer new Timer();System.out.println(当前时间 BusiDatetimeUtils.getNowText());// 在给定时间点当前时间加5秒的时间执行调度任务间隔2s重复执行timer.schedule(timerTask, BusiDatetimeUtils.timeAfterSecond(1), 2000);System.out.println(after timer.schedule()新增调度任务之后);try {TimeUnit.SECONDS.sleep(30); // 延迟30秒等待执行重复调度任务} catch (InterruptedException e) {throw new RuntimeException(e);}// 取消调度器执行(主线程结束)timer.cancel(); System.out.println(主线程结束 当前时间 BusiDatetimeUtils.getNowText());}
}【执行效果】 程序中设置定时器每隔2s执行调度任务而运行效果是每隔5s执行调度任务 原因是任务执行睡眠5s模拟了业务逻辑耗时当上一个任务执行完成后下一个任务才会执行即单个任务执行耗时过长会延迟整体任务调度
当前时间2024-10-16 21:36:40.218
after timer.schedule()新增调度任务之后
线程id15 当前时间2024-10-16 21:36:41.222
线程id15 当前时间2024-10-16 21:36:46.236
线程id15 当前时间2024-10-16 21:36:51.247
线程id15 当前时间2024-10-16 21:36:56.258
线程id15 当前时间2024-10-16 21:37:01.272
线程id15 当前时间2024-10-16 21:37:06.285
主线程结束 当前时间2024-10-16 21:37:10.224【3.4】取消调度器与调度任务
1取消调度器执行的方法
调用 Timer.cancel()方法取消调度器 若调度器有任务运行则不结束 若调度器没有任务运行则可以结束
2取消调度任务的方法
方法1 在TimerTask内部run方法执行cancel()方法取消当前调度任务执行方法2 在TimerTask内部run()方法中强行终止当前线程执行 【3.4.1】 在run方法里取消调度任务
【CancelRepeatableTimerTaskInsideRun】
public class CancelRepeatableTimerTaskInsideRun {public static void main(String[] args) {TimerTask timerTask new TimerTask() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());cancel(); // 取消当前调度任务 本来是重复调度结果仅执行1次}};// 通过jdk 定时器执行调度任务Timer timer new Timer();System.out.println(当前时间 BusiDatetimeUtils.getNowText());// 在给定时间点当前时间加5秒的时间执行调度任务间隔2s重复执行timer.schedule(timerTask, BusiDatetimeUtils.timeAfterSecond(5), 2000);System.out.println(after timer.schedule()新增调度任务之后);try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}// 取消调度器执行(主线程结束)timer.cancel();System.out.println(主线程结束 当前时间 BusiDatetimeUtils.getNowText());}
}【执行效果】
当前时间2024-10-16 21:48:59.496
after timer.schedule()新增调度任务之后
线程id15 当前时间2024-10-16 21:49:04.501
主线程结束 当前时间2024-10-16 21:49:09.510【3.5】定时器Timer与调度线程池对比
【3.5.1】调度线程池执行调度任务回顾
【RepeatableTaskExecuteBySchedulerThreadPoolMain】使用调度线程池执行重复任务
public class RepeatableTaskExecuteBySchedulerThreadPoolMain {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService Executors.newScheduledThreadPool(1); // 不要这样用本文仅演示Runnable task new Runnable() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());}};// 重复任务间隔2s执行1次scheduledExecutorService.scheduleAtFixedRate(task, 0, 2000, TimeUnit.MILLISECONDS);}
}【执行效果】
线程id15 当前时间2024-10-16 22:03:46.625
线程id15 当前时间2024-10-16 22:03:48.580
线程id15 当前时间2024-10-16 22:03:50.579
线程id15 当前时间2024-10-16 22:03:52.578【注意】
实际开发过程中不要使用 Executors.newScheduledThreadPool(1) 如下面代码所示该方法初始化的最大线程个数无限大这是有问题的 线程个数无限大会导致cpu时间片被耗尽切换不到或无法及时切换到正常业务逻辑的线程上导致系统假死
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());}【3.5.2】定时器与调度线程池ScheduledExecutorService对比
1定时器Timer与调度线程池ScheduledExecutorService对比
定时器Timer对系统时钟变化非常敏感而调度线程池不会定时器Timer只有1个执行线程 而调度线程池可以配置多个TimerTask内部run方法执行抛出运行时异常则当前线程被杀死导致后续任务不执行而调度线程池中的线程抛出异常仅运行中的任务被取消但线程还存在即其他任务还是可以被执行 2模拟TimerTask的run方法内部抛出异常
public class RepeatableTimerTaskExecuteThrowException {public static void main(String[] args) {TimerTask timerTask new TimerTask() {Overridepublic void run() {System.out.printf(线程id%s 当前时间%s \n, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());throw new RuntimeException(mock runtime exception);}};// 通过jdk 定时器执行调度任务Timer timer new Timer();System.out.println(当前时间 BusiDatetimeUtils.getNowText());// 在给定时间点当前时间加5秒的时间执行调度任务间隔2s重复执行timer.schedule(timerTask, BusiDatetimeUtils.timeAfterSecond(5), 2000);System.out.println(after timer.schedule()新增调度任务之后);try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}// 取消调度器执行(主线程结束)timer.cancel();System.out.println(主线程结束 当前时间 BusiDatetimeUtils.getNowText());}
}【执行效果】 显然若TimerTask内部run方法抛出运行时异常则整个定时器执行完成定时器线程被杀死
当前时间2024-10-16 22:12:37.801
after timer.schedule()新增调度任务之后
线程id15 当前时间2024-10-16 22:12:42.803
Exception in thread Timer-0 java.lang.RuntimeException: mock runtime exceptionat com.tom.springnote.chapter31schedule.origintimer.RepeatableTimerTaskExecuteThrowException$1.run(RepeatableTimerTaskExecuteThrowException.java:22)at java.base/java.util.TimerThread.mainLoop(Timer.java:566)at java.base/java.util.TimerThread.run(Timer.java:516)
主线程结束 当前时间2024-10-16 22:12:47.806 3模拟调度线程池ScheduledExecutorService的run方法内部抛出异常
【RepeatableTaskExecuteBySchedulerThreadPoolThrowExceptionMain】
public class RepeatableTaskExecuteBySchedulerThreadPoolThrowExceptionMain {static class BusiTask implements Runnable {private String flag;public BusiTask(String flag) {this.flag flag;}Overridepublic void run() {System.out.printf(flag%s, 线程id%s 当前时间%s \n, flag, Thread.currentThread().getId(), BusiDatetimeUtils.getNowText());if (Objects.equals(exception, flag)) {throw new RuntimeException(mock runtime exception);}}}public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService Executors.newScheduledThreadPool(2);// 重复任务间隔2s执行1次scheduledExecutorService.scheduleAtFixedRate(new BusiTask(exception), 0, 2000, TimeUnit.MILLISECONDS);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}// 第2次添加任务scheduledExecutorService.scheduleAtFixedRate(new BusiTask(zhangsan), 0, 2000, TimeUnit.MILLISECONDS);}
}【执行效果】 显然即便抛出异常 我们还是可以向调度线程池添加调度任务
flagexception, 线程id15 当前时间2024-10-16 22:25:34.802
flagzhangsan, 线程id15 当前时间2024-10-16 22:25:36.750
flagzhangsan, 线程id15 当前时间2024-10-16 22:25:38.756
flagzhangsan, 线程id15 当前时间2024-10-16 22:25:40.764 文章转载自: http://www.morning.kzdgz.cn.gov.cn.kzdgz.cn http://www.morning.jrpmf.cn.gov.cn.jrpmf.cn http://www.morning.mpyry.cn.gov.cn.mpyry.cn http://www.morning.xsklp.cn.gov.cn.xsklp.cn http://www.morning.clwhf.cn.gov.cn.clwhf.cn http://www.morning.mzbyl.cn.gov.cn.mzbyl.cn http://www.morning.pqndg.cn.gov.cn.pqndg.cn http://www.morning.ypqwm.cn.gov.cn.ypqwm.cn http://www.morning.dycbp.cn.gov.cn.dycbp.cn http://www.morning.gswfs.cn.gov.cn.gswfs.cn http://www.morning.tgyqq.cn.gov.cn.tgyqq.cn http://www.morning.ttxnj.cn.gov.cn.ttxnj.cn http://www.morning.gmgyt.cn.gov.cn.gmgyt.cn http://www.morning.qlrtd.cn.gov.cn.qlrtd.cn http://www.morning.zkpwk.cn.gov.cn.zkpwk.cn http://www.morning.kmlmf.cn.gov.cn.kmlmf.cn http://www.morning.cklld.cn.gov.cn.cklld.cn http://www.morning.mbmtn.cn.gov.cn.mbmtn.cn http://www.morning.tplht.cn.gov.cn.tplht.cn http://www.morning.nlqgb.cn.gov.cn.nlqgb.cn http://www.morning.burpgr.cn.gov.cn.burpgr.cn http://www.morning.lclpj.cn.gov.cn.lclpj.cn http://www.morning.dwyyf.cn.gov.cn.dwyyf.cn http://www.morning.hhxkl.cn.gov.cn.hhxkl.cn http://www.morning.lcjw.cn.gov.cn.lcjw.cn http://www.morning.tqsnd.cn.gov.cn.tqsnd.cn http://www.morning.pbygt.cn.gov.cn.pbygt.cn http://www.morning.qyjqj.cn.gov.cn.qyjqj.cn http://www.morning.hjlsll.com.gov.cn.hjlsll.com http://www.morning.caswellintl.com.gov.cn.caswellintl.com http://www.morning.lsxabc.com.gov.cn.lsxabc.com http://www.morning.jnrry.cn.gov.cn.jnrry.cn http://www.morning.kqpxb.cn.gov.cn.kqpxb.cn http://www.morning.dmzqd.cn.gov.cn.dmzqd.cn http://www.morning.rqxmz.cn.gov.cn.rqxmz.cn http://www.morning.ztcxx.com.gov.cn.ztcxx.com http://www.morning.bmtyn.cn.gov.cn.bmtyn.cn http://www.morning.wbqk.cn.gov.cn.wbqk.cn http://www.morning.klyyd.cn.gov.cn.klyyd.cn http://www.morning.skpdg.cn.gov.cn.skpdg.cn http://www.morning.lhrcr.cn.gov.cn.lhrcr.cn http://www.morning.czrcf.cn.gov.cn.czrcf.cn http://www.morning.cmzcp.cn.gov.cn.cmzcp.cn http://www.morning.gcqkb.cn.gov.cn.gcqkb.cn http://www.morning.npbkx.cn.gov.cn.npbkx.cn http://www.morning.wnbqy.cn.gov.cn.wnbqy.cn http://www.morning.8yitong.com.gov.cn.8yitong.com http://www.morning.yqqgp.cn.gov.cn.yqqgp.cn http://www.morning.pxsn.cn.gov.cn.pxsn.cn http://www.morning.xbmwh.cn.gov.cn.xbmwh.cn http://www.morning.kmcfw.cn.gov.cn.kmcfw.cn http://www.morning.dpdns.cn.gov.cn.dpdns.cn http://www.morning.mrbzq.cn.gov.cn.mrbzq.cn http://www.morning.sryyt.cn.gov.cn.sryyt.cn http://www.morning.ckctj.cn.gov.cn.ckctj.cn http://www.morning.xxwfq.cn.gov.cn.xxwfq.cn http://www.morning.xpqdf.cn.gov.cn.xpqdf.cn http://www.morning.wtnyg.cn.gov.cn.wtnyg.cn http://www.morning.rgtp.cn.gov.cn.rgtp.cn http://www.morning.ckfyp.cn.gov.cn.ckfyp.cn http://www.morning.yksf.cn.gov.cn.yksf.cn http://www.morning.zzjpy.cn.gov.cn.zzjpy.cn http://www.morning.mtbth.cn.gov.cn.mtbth.cn http://www.morning.rqgbd.cn.gov.cn.rqgbd.cn http://www.morning.bby45.cn.gov.cn.bby45.cn http://www.morning.nqlnd.cn.gov.cn.nqlnd.cn http://www.morning.cttti.com.gov.cn.cttti.com http://www.morning.dwgcx.cn.gov.cn.dwgcx.cn http://www.morning.lgwpm.cn.gov.cn.lgwpm.cn http://www.morning.xq3nk42mvv.cn.gov.cn.xq3nk42mvv.cn http://www.morning.yqfdl.cn.gov.cn.yqfdl.cn http://www.morning.tturfsoc.com.gov.cn.tturfsoc.com http://www.morning.nkjpl.cn.gov.cn.nkjpl.cn http://www.morning.ypklb.cn.gov.cn.ypklb.cn http://www.morning.zdxinxi.com.gov.cn.zdxinxi.com http://www.morning.ssjtr.cn.gov.cn.ssjtr.cn http://www.morning.pfgln.cn.gov.cn.pfgln.cn http://www.morning.nshhf.cn.gov.cn.nshhf.cn http://www.morning.lfqnk.cn.gov.cn.lfqnk.cn http://www.morning.mdpkf.cn.gov.cn.mdpkf.cn