谈谈任务调度的四种实现方式
一、什么是任务调度
任务调度是指基于给定时间点,给定时间间隔或者给定执行次数自动执行任务,本文会介绍Timer、ScheduledExecutor、Quartz、Spring Boot中的调度模块使用。
二、Timer
Timer任务调度的核心类是 Timer 和 TimerTask。其中Timer负责设定TimerTask的起始与间隔执行时间。使用者只需要创建一个 TimerTask 的继承类,实现自己的run方法,然后将其丢给 Timer 去执行即可。
下面的例子每隔半秒执行run中的方法,输出当前时间和name。
public class Main {public static void main(String[] args) throws ClassNotFoundException {Timer timer = new Timer();timer.schedule(new TestTimerTask("test"), 0, 500);}static class TestTimerTask extends TimerTask {private String name;public TestTimerTask(String name) {this.name = name;}@Overridepublic void run() {System.out.println(LocalDateTime.now()+"-----run----" + name);}}
}
运行结果:
2020-05-19T09:19:11.301-----run----test
2020-05-19T09:19:11.741-----run----test
2020-05-19T09:19:12.241-----run----test
2020-05-19T09:19:12.742-----run----test
2020-05-19T09:19:13.242-----run----test
2020-05-19T09:19:13.742-----run----test
2020-05-19T09:19:14.242-----run----test
2020-05-19T09:19:14.743-----run----test
2020-05-19T09:19:15.243-----run----test
2020-05-19T09:19:15.743-----run----test
2020-05-19T09:19:16.244-----run----test
2020-05-19T09:19:16.743-----run----test
2020-05-19T09:19:17.243-----run----test
因为Timer底层是使用一个单线来实现多个Timer任务处理的,所有任务都是由同一个线程来调度,所有任务都是串行执行,意味着同一时间只能有一个任务得到执行,而某一个任务的延迟或者异常会影响到之后的任务。如下面这段,当test2抛出异常后,test也会终止。
public class Main {public static void main(String[] args) throws ClassNotFoundException {Timer timer = new Timer();timer.schedule(new TestTimerTask("test"), 0, 500);timer.schedule(new TestTimerTask("test2"), 0, 500);}static class TestTimerTask extends TimerTask {private String name;private int count ;public TestTimerTask(String name) {this.name = name;}@Overridepublic void run() {if ("test2".equals(name)){count++;if (count>5){throw new NullPointerException();}}System.out.println(LocalDateTime.now()+"-----run----" + name);}}
}
三、ScheduledExecutor
鉴于 Timer 的上述缺陷,Java 5 推出了基于线程池设计的 ScheduledExecutor。其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。
下面这段是每隔一秒执行一次任务。
public class Main {public static void main(String[] args) throws ClassNotFoundException {ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);scheduledExecutorService.scheduleWithFixedDelay(new TestRunnable("test1"),0,1, TimeUnit.SECONDS);}static class TestRunnable implements Runnable{private String name;public TestRunnable(String name) {this.name = name;}@Overridepublic void run() {System.out.println(LocalDateTime.now()+"-----run----" + name);}}
}
运行结果:
2020-05-19T09:30:07.005-----run----test1
2020-05-19T09:30:08.005-----run----test1
2020-05-19T09:30:09.006-----run----test1
2020-05-19T09:30:10.006-----run----test1
ScheduledExecutorService中常用的调度方法是scheduleAtFixedRate和scheduleWithFixedDelay。
scheduleAtFixedRate每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为 :initialDelay, initialDelay+period, initialDelay+2*period, …。
scheduleWithFixedDelay每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDelay, initialDelay+executeTime+delay, initialDelay+2executeTime+2delay。由此可见,scheduleAtFixedRate是基于固定时间间隔进行任务调度,ScheduleWithFixedDelay取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。
四、Quartz
Quartz是一个由OpenSymphony组织开源的java调度框架。特点如下。
(1)具有强大的调度功能,很容易与spring集成,形成灵活可配置的调度功能。
(2)调度环境的持久化机制:可以保存并恢复调度现场,即使系统因为故障关闭,任务调度现场的数据并不会丢失。
(3)灵活的应用方式:可以灵活的定义触发器调度的时间表,并可以对触发器与任务进行关联映射;
(4)分布式与集群能力。
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version></dependency>
下面这段还是每隔1秒打印当前时间。
public class Main {public static void main(String[] args) throws SchedulerException {JobDetail jobDetail =JobBuilder.newJob(SimpleQuartzJob.class).withIdentity("testJob","group").build();SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "group").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever()).build();StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();Scheduler scheduler = stdSchedulerFactory.getScheduler();scheduler.start();scheduler.scheduleJob(jobDetail,trigger);}
}public class SimpleQuartzJob implements Job {public SimpleQuartzJob() {}public void execute(JobExecutionContext context) throws JobExecutionException {System.out.println(LocalDateTime.now()+" "+context.getJobDetail().getKey().getName());}
}
Quartz 设计的核心类包括 Scheduler, Job 以及 Trigger。其中,Job 负责定义需要执行的任务,Trigger 负责设置调度策略,Scheduler 将二者组装在一起,并触发任务开始执行。
另外Quartz也支持cron表达式,如下,*/1 * * * * ?
为每隔1秒执行一次。
public class Main {public static void main(String[] args) throws SchedulerException {JobDetail jobDetail =JobBuilder.newJob(SimpleQuartzJob.class).withIdentity("testJob","group").build();
// SimpleTrigger trigger = TriggerBuilder.newTrigger()
// .withIdentity("testTrigger", "group")
// .startNow()
// .withSchedule(SimpleScheduleBuilder.simpleSchedule()
// .withIntervalInSeconds(1).
// repeatForever()).build();CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "group").startNow().withSchedule(CronScheduleBuilder.cronSchedule("*/1 * * * * ?")).build();StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();Scheduler scheduler = stdSchedulerFactory.getScheduler();scheduler.start();scheduler.scheduleJob(jobDetail,trigger);}
}
五、Spring Boot中任务调度
在Spring Boot中开发定时任务需要在启动类上增加一个@EnableScheduling注解来开启定时任务功能。
其次,使用@Component注解标注一个类,在其需要定时执行的方法上添加@Scheduled注解。
@Component
public class TestScheduled {@Scheduled(fixedDelay = 3000)public void test1(){System.out.println(LocalDateTime.now()+" fixedDelay");}@Scheduled(fixedRate = 5000)public void test2(){System.out.println(LocalDateTime.now()+" fixedRate");}@Scheduled(cron = "*/1 * * * * ?")public void test3(){System.out.println(LocalDateTime.now()+" cron");}
}
@Scheduled中的参数如下:@Scheduled(fixedDelay = 3000):上次执行完毕后时间后3秒再次执行。@Scheduled(fixedRate = 5000):上次开始执行时间点后5秒再次执行。@Scheduled(cron = "*/1 * * * * ?"):按照cron表达式规则执行。
谈谈任务调度的四种实现方式相关推荐
- 简单谈谈OAuth 2.0的四种认证方式
简单谈谈OAuth 2.0的四种认证方式 一.基本认识 1.1 OAuth认证中的四种角色 二.认证方式 2.1 授权码认证 2.2 简化认证 2.3 密码认证 2.4 客户端认证 一.基本认识 在小 ...
- RxJS的另外四种实现方式(一)——代码最小的库
2019独角兽企业重金招聘Python工程师标准>>> 接上篇RxJS的另外四种实现方式(序) 起因 想到这个库的原因,是看了callbag库想到的,callbag库的原理大家可以自 ...
- JAVA四种引用方式
JAVA四种引用方式: java.lang.ref: 强引用(直接变量赋值) 软引用(SoftReference): 只有在要发生OOM错误之前才会回收掉老的软引用对象,应用场景主要防止内存溢出.(缓 ...
- 矩阵乘法的四种理解方式
先介绍向量的两种运算,一个行向量乘以一个列向量称作向量的内积,又叫作点积,结果是一个数: 一个列向量乘以一个行向量称作向量的外积,外积是一种特殊的克罗内克积,结果是一个矩阵, 假设和b分别是一个行向量 ...
- 【Android】android开发之splash闪屏页的四种实现方式,启动页的实现教程。
2019独角兽企业重金招聘Python工程师标准>>> 作者:程序员小冰,GitHub主页: https://github.com/QQ986945193 新浪微博:http://w ...
- sqlserver的四种分页方式
第一种:ROW_NUMBER() OVER()方式 select * from ( select *, ROW_NUMBER() OVER(Order by ArtistId ) AS RowId f ...
- 【Python基础】Python爬虫的两套解析方法和四种信息提取方式
Python爬虫 Author:Iouwill Machine Learning Lab 分享一篇往日旧文章,非常实用. 对于大多数朋友而言,爬虫绝对是学习python的最好的起手和入门方式.因为爬虫 ...
- OAuth2.0的四种授权方式
在OAuth2.0中,OAuth2.0 provider负责保护暴露在外的资源,第三方应用客户端Client可以独立的或代表用户Owner来访问这些受保护的资源,provider提供token令牌的管 ...
- php xml 四种,xml中常见的四种解析方式是什么?
xml解析方式有:1.DOM解析方法,可以对xml文档进行修改操作:2.SAX解析方法,解析速度快,占用内存少:3.JDOM解析方法,查找方便:4.DOM4J解析方法,解析XML的速度快. 在XML的 ...
- 对require四种引入方式的认识
对require四种引入方式的认识: 转载于:https://www.cnblogs.com/461770539-qq/p/9357485.html
最新文章
- 安卓模拟器BlueStacks 安装使用教程(图解)
- SpringBoot - 优雅的处理【长事务】
- TopFreeTheme精选免费模板【20130701.特别版】
- python six库_six库 解决python2的项目如何能够完全迁移到python3
- vue 怎么清空依赖_vuejs如何在把对象所有属性清空?
- bash: vim: command not found
- 建立企业内部maven服务器并使用Android Studio发布公共项目
- 那些炫酷的特效--QQ空间+VUE
- 四轮定位和四轮动平衡有什么区别?
- AcWing 904. 虫洞(SPFA or Djakarta or bellman判负环)
- 论Webstorm汉化后无法打开配置
- vue 判断是否是微信浏览器
- adb命令刷机vivox20_vivo手机变砖 刷机手机端口连上显示adb
- 云计算与大数据之间的关系
- 关于计算机的想象类作文,想象类作文范文
- instant-ngp总结
- latex中极限号下边怎么打_latex 极限下标
- 基于SSH会员积分消费管理系统
- 网络加速技术浅析(二)
- Linux系统如何更新升级
热门文章
- plotyy函数_plotyy函数参数设置
- emi滤波matlab,EMI滤波器的作用和种类
- JVM 为什么使用元空间替换了永久代?
- 静态IP、动态IP、ADSL拨号和DNS这几者你分得清吗?
- 有IPV6无法登录IPV6网站*
- 如何跳过计算机配置直接开机,WIN7开机怎么跳过欢迎界面_win7怎样跳过电脑开机欢迎界面-win7之家...
- 亚马逊Rating和Review的这些区别你知多少?
- 【web攻防】CVE-2020-10487 tomcat 文件包含漏洞 docker 复现学习
- python太阳代码_用86行Python代码模拟太阳系
- 在解压缩某些文件时出现问题检查计算机上,rar文件解压缩失败解压末端出现错误的解决方法...