Java并发39:Executor系列--ScheduleExecutorService接口学习笔记
[超级链接:Java并发学习系列-绪论]
本章主要学习ScheduleExecutorService接口。
1.ScheduleExecutorService接口概述
@since 1.5
ScheduledExecutorService继承自ExecutorService,它可以在给定延时之后调度任务,也可以以指定的周期调度任务。
schedule()方法可以创建含有延时(delays)变量的任务,然后返回一个可以用于取消或检查运行状态的Future对象。
scheduleAtFixedRate()方法和scheduleWithFixedDelay()方法可以创建并运行定期运行的任务。
通过Executor#execute(Runnable)方法和ExecutorService.submit()方法提交的命令会作为零延时(delay=0)的任务被调度。
在调用schedule()方法时,如果传递0或者负值的延时参数,这些任务将被当做立刻执行的任务。
所有的schedule()方法都接收相对延时和周期作为参数,但是并不接受绝对时间或者绝对日期。
将java.util.Date表示的绝对日期转换成一个绝对日期是一件很简单的事情。
例如,计划在将来的某个时刻执行任务,你可以这么做:
schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
但是需要注意,由于时间同步协议、时钟漂移或其他因素,相对延时的到期时间未必与预期的Date时间一致。
Executors工具类提供了方便的工厂方法用于实现ScheduledExecutorService。
示例
下面这个类的beepForAnHour
方法启动了一个ScheduledExecutorService服务,这个服务每个小时内有10秒发出哔哔哔的声音。
import static java.util.concurrent.TimeUnit.*;
class BeeperControl {private final ScheduledExecutorService scheduler =Executors.newScheduledThreadPool(1);public void beepForAnHour() {final Runnable beeper = new Runnable() {public void run() {System.out.println("beep");}};final ScheduledFuture<?> beeperHandle =scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);scheduler.schedule(new Runnable() {public void run() {beeperHandle.cancel(true);}}, 60 * 60, SECONDS);}
}
2.Executor、ExecutorService与ScheduleExecutorService
下面对Executor、ExecutorService和ScheduleExecutorService三个接口的特性进行简单的说明:
- Executor
- 执行Runnable接口:execute
- ExecutorService
- 执行Runnable接口:execute
- 手动关闭:shutdown、shutdownNow
- 执行Future和Callable接口:submit、invokeAll、invokeAny
- ScheduleExecutorService
- 执行Runnable接口:execute
- 手动关闭:shutdown、shutdownNow
- 执行Future和Callable接口:submit、invokeAll、invokeAny
- 延时调度、周期调度:schedule、scheduleWithFixedDelay、scheduleAtFixedRate
3.ScheduleExecutorService方法说明
ScheduleExecutorService的延时调度、周期调度相关方法如下:
1.schedule(Runnable command,long delay, TimeUnit unit)
- 在一定延时(delay)之后,运行Runnable任务。
- 此任务只运行一次。
2.schedule(Callable callable,long delay, TimeUnit unit)
- 在一定延时(delay)之后,运行Callable任务。
- 此任务只运行一次。
3.scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)
- 在一定延时(initialDelay)之后,开始周期性的运行Runnable任务。
- 周期性:上一次任务执行完成之后,等待一段时间(delay),然后开始下一次任务。
4.scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
- 在一定延时(initialDelay)之后,开始周期性的运行Runnable任务。
- 周期性:每过一段时间(period),就开始运行一次Runnable任务。
- 如果任务的执行时间大于等待周期(period):
- 上一次任务执行完成之后,立即开始下一次任务。
- 也就是说:每过一段时间(任务执行时间),就开始运行一次Runnable任务。
4.实例练习
练习目的:掌握延时调度任务和周期调度任务的方法的用法。
练习内容:
- 分别实现以下调度任务:
- 方式1:通过schedule方法实现:2秒之后打印系统时间。
- 方式2:通过scheduleWithFixedDelay方法实现:5秒之后开始周期性的打印系统时间,连续两次打印间隔为3秒(delay),每次打印耗时2秒。
- 方式3:通过scheduleAtFixedRate方法实现:5秒之后开始周期性的打印系统时间,每3秒(period)打印一次,每次打印耗时2秒。
- 方式3:通过scheduleAtFixedRate方法实现:5秒之后开始周期性的打印系统时间,每2秒(period)打印一次,每次打印耗时3秒。
实例代码:
/*** <p>ScheduleExecutorService</p>** @author hanchao 2018/4/5 12:50**/
public static void main(String[] args) throws InterruptedException, ExecutionException {/*Executor 执行Runnable接口ExecutorService 执行Runnable接口、手动关闭、执行Future和Callable接口(单个、任一、批量)ScheduleExecutorService 执行Runnable接口、手动关闭、执行Future和Callable接口(单个、任一、批量)、延时执行Runnable接口和Callable接口、周期执行Runnable接口(2种方式)*/ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);/*0 schedule 延时执行Runnable和延时执行Callable 执行一次1 scheduleWithFixedDelay 周期性的延时执行Runnable接口 上一次任务结束和下一次任务开始之间的时间间隔是固定的=delay2 scheduleAtFixedRate 周期性的等速率执行Runnable接口 上一次任务开始和下一次任务开始之间的时间间隔是固定的=period3 scheduleAtFixedRate 周期性的等速率执行Runnable接口 如果任务执行时间大于period,则上一次任务结束之后,立即开始下一次任务;即period=任务执行时间*/int type = 0;switch (type) {case 0://延时执行Runnable接口LOGGER.info("延时执行Runnable接口 : " + System.currentTimeMillis());scheduledExecutorService.schedule(() -> {LOGGER.info("2秒之后 : " + System.currentTimeMillis());}, 2000, TimeUnit.MILLISECONDS);Thread.sleep(2500);//延时执行Callable接口System.out.println();LOGGER.info("延时执行Callable接口 : " + System.currentTimeMillis());ScheduledFuture scheduledFuture = scheduledExecutorService.schedule(() -> {return System.currentTimeMillis();}, 2, TimeUnit.SECONDS);LOGGER.info("2秒之后 :" + scheduledFuture.get());//等待多长时间Thread.sleep(1000);break;case 1://周期性的延时执行//初始延时long initDelay = 5000;//延时long delay = 3000;LOGGER.info("周期性的延时执行Runnable接口 : " + System.currentTimeMillis());//周期性的延时执行scheduledExecutorService.scheduleWithFixedDelay(() -> {int number = RandomUtils.nextInt(1000, 3000);LOGGER.info("周期性的延时执行Runnable接口 [" + number + "]开始运行 : " + System.currentTimeMillis());//模拟运行try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}LOGGER.info("周期性的延时执行Runnable接口 [" + number + "]结束运行 : " + System.currentTimeMillis());}, initDelay, delay, TimeUnit.MILLISECONDS);//等待多长时间Thread.sleep(20000);break;case 2://初始延时long initDelay1 = 5000;//执行周期long period = 3000;LOGGER.info("周期性的延时执行Runnable接口 : " + System.currentTimeMillis());//周期性的执行scheduledExecutorService.scheduleAtFixedRate(() -> {int number = RandomUtils.nextInt(1000, 3000);LOGGER.info("周期性的延时执行Runnable接口 [" + number + "]开始运行 : " + System.currentTimeMillis());//模拟运行try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}
// LOGGER.info("周期性的延时执行Runnable接口 [" + number + "]结束运行 : " + System.currentTimeMillis());}, initDelay1, period, TimeUnit.MILLISECONDS);//等待多长时间Thread.sleep(20000);break;case 3://初始延时long initDelay2 = 5000;//执行周期long period1 = 2000;LOGGER.info("周期性的延时执行Runnable接口 : " + System.currentTimeMillis());//周期性的执行scheduledExecutorService.scheduleAtFixedRate(() -> {int number = RandomUtils.nextInt(1000, 3000);LOGGER.info("周期性的延时执行Runnable接口 [" + number + "]开始运行 : " + System.currentTimeMillis());//模拟运行try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}LOGGER.info("周期性的延时执行Runnable接口 [" + number + "]结束运行 : " + System.currentTimeMillis());}, initDelay2, period1, TimeUnit.MILLISECONDS);//等待多长时间Thread.sleep(20000);break;default:break;}//如果没关闭,则关闭if (!scheduledExecutorService.isShutdown()) {scheduledExecutorService.shutdown();}
}
type=0时,调用schedule,执行结果:
2018-04-06 16:26:18 INFO - 延时执行Runnable接口 : 1523003178598
2018-04-06 16:26:20 INFO - 2秒之后 : 15230031806442018-04-06 16:26:21 INFO - 延时执行Callable接口 : 1523003181144
2018-04-06 16:26:23 INFO - 2秒之后 :1523003183146
无论是Runnable还是Callable任务,都只是执行了一次。
type=1时,调用scheduleWithFixedDelay,执行结果:
2018-04-06 16:30:24 INFO - 周期性的延时执行Runnable接口 : 1523003424210
2018-04-06 16:30:29 INFO - 周期性的延时执行Runnable接口 [1513]开始运行 : 1523003429281
2018-04-06 16:30:31 INFO - 周期性的延时执行Runnable接口 [1513]结束运行 : 1523003431281
2018-04-06 16:30:34 INFO - 周期性的延时执行Runnable接口 [2579]开始运行 : 1523003434282
2018-04-06 16:30:36 INFO - 周期性的延时执行Runnable接口 [2579]结束运行 : 1523003436282
2018-04-06 16:30:39 INFO - 周期性的延时执行Runnable接口 [2347]开始运行 : 1523003439283
2018-04-06 16:30:41 INFO - 周期性的延时执行Runnable接口 [2347]结束运行 : 1523003441284
上一次任务结束 与 下一次任务开始 的间隔 = delay = 3秒
type=2时,调用scheduleAtFixedRate,执行结果:
2018-04-06 16:33:48 INFO - 周期性的延时执行Runnable接口 : 1523003628760
2018-04-06 16:33:53 INFO - 周期性的延时执行Runnable接口 [2601]开始运行 : 1523003633808
2018-04-06 16:33:56 INFO - 周期性的延时执行Runnable接口 [2189]开始运行 : 1523003636804
2018-04-06 16:33:59 INFO - 周期性的延时执行Runnable接口 [2071]开始运行 : 1523003639804
2018-04-06 16:34:02 INFO - 周期性的延时执行Runnable接口 [2399]开始运行 : 1523003642803
2018-04-06 16:34:05 INFO - 周期性的延时执行Runnable接口 [1743]开始运行 : 1523003645803
2018-04-06 16:34:08 INFO - 周期性的延时执行Runnable接口 [2351]开始运行 : 1523003648804
上一次任务开始 与 下一次任务开始 的间隔 = delay = 3秒
type=3时,调用scheduleAtFixedRate,执行结果:
2018-04-06 16:35:04 INFO - 周期性的延时执行Runnable接口 : 1523003704193
2018-04-06 16:35:09 INFO - 周期性的延时执行Runnable接口 [1614]开始运行 : 1523003709250
2018-04-06 16:35:12 INFO - 周期性的延时执行Runnable接口 [1614]结束运行 : 1523003712250
2018-04-06 16:35:12 INFO - 周期性的延时执行Runnable接口 [2846]开始运行 : 1523003712250
2018-04-06 16:35:15 INFO - 周期性的延时执行Runnable接口 [2846]结束运行 : 1523003715251
2018-04-06 16:35:15 INFO - 周期性的延时执行Runnable接口 [2760]开始运行 : 1523003715252
2018-04-06 16:35:18 INFO - 周期性的延时执行Runnable接口 [2760]结束运行 : 1523003718253
2018-04-06 16:35:18 INFO - 周期性的延时执行Runnable接口 [2262]开始运行 : 1523003718253
2018-04-06 16:35:21 INFO - 周期性的延时执行Runnable接口 [2262]结束运行 : 1523003721255
2018-04-06 16:35:21 INFO - 周期性的延时执行Runnable接口 [2565]开始运行 : 1523003721255
2018-04-06 16:35:24 INFO - 周期性的延时执行Runnable接口 [2565]结束运行 : 1523003724256
因为任务的执行时间(3秒)大于开始任务的周期period(2秒),所以:
- 上一次任务开始 与 下一次任务开始 的间隔时间 = 任务执行时间
- 上一次任务结束 与 下一次任务开始 的间隔 0 秒
Java并发39:Executor系列--ScheduleExecutorService接口学习笔记相关推荐
- Java并发23:Atomic系列-普通原子类型AtomicXxxx学习笔记
[超级链接:Java并发学习系列-绪论] [系列概述: Java并发22:Atomic系列-原子类型整体概述与类别划分] 本章主要对普通原子类型进行学习. 1.普通原子类型 在java.util.co ...
- Java 并发编程——Executor框架和线程池原理
Java 并发编程系列文章 Java 并发基础--线程安全性 Java 并发编程--Callable+Future+FutureTask java 并发编程--Thread 源码重新学习 java并发 ...
- Java并发26:Atomic系列-ABA问题-带版本戳的原子引用类型AtomicStampedReference与AtomicMarkableReference
[超级链接:Java并发学习系列-绪论] [系列概述: Java并发22:Atomic系列-原子类型整体概述与类别划分] 本章主要对带版本戳的原子引用类型进行学习. 1.ABA问题 带版本戳的原子引用 ...
- Java自学.接口学习笔记!
接口学习笔记 文章目录 接口学习笔记 1.接口的概述与生活中的举例 2.接口定义的基本格式 3.接口的抽象方法 3.1接口抽象方法的定义 3.2接口的抽象方法使用 4.接口的默认方式 4.1接口的默认 ...
- 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...
- 《Java并发编程实践-第一部分》-读书笔记
大家好,我是烤鸭: <Java并发编程实战-第一部分>-读书笔记. 第一章:介绍 1.1 并发历史: 多个程序在各自的进程中执行,由系统分配资源,如:内存.文件句柄.安全证书.进程间通信方 ...
- Java中如何创建自定义的注解学习笔记(MD版)
概要 Java中如何创建自定义的注解学习笔记(MD版). 博客 博客地址:IT老兵驿站. 前言 记得这篇笔记还是在泉州的龙玲酒店记录的,是一个周六的晚上,坐飞机从上海到泉州,从笔记中能勾起一些旅游的回 ...
- 阿里云Apsara Clouder专项技能认证-实现调用API接口-学习笔记
Apsara Clouder专项技能认证-实现调用API接口-学习笔记 阿里云的一个小认证,闲来无事,考一下 一.API简介 API的概念 API(Application Programming In ...
- (实验39)单片机,STM32F4学习笔记,代码讲解【FATFS实验】【正点原子】【原创】
文章目录 其它文章链接,独家吐血整理 实验现象 主程序 FATFS初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创 ...
最新文章
- php set name,PHP Gmagick setfilename()用法及代码示例
- 数据中心IT机房末端气流组织管理
- 提领指向不完全类型的指针_望远镜不完全指南:望远镜原理、类型和配件
- as3 java 交互_AS3常用代码(三):AS3与HTML的交互
- 【vue】跟着老马学习vue-数据双向绑定
- c++ 基本排序算法学习
- Astyle 一键格式化项目代码
- Flash 与数学:圆的切线(3)
- 日均万亿条数据如何处理?爱奇艺实时计算平台这样做
- python可视化库matplotlib_Python数据可视化matplotlib库
- 【kafka】Flink 消费 kafka Received unknown topic topic/partition may not exist Describe access to it
- Java抽象类/接口
- 《冒号课堂》精彩书评集萃
- 计算机程序配置不正确 请联系我们,电脑应用程序配置不正确怎么办
- [树形DP]贪吃的九头龙
- 嵌入式C语言学习笔记附图
- 【Coursera】深度神经网络的改进:超参数调整、正则化和优化(更新中2023/04/12)
- kiwix 离线维基百科_离线内容提供商Kiwix背后的故事
- 网络 | email
- 人工智能术语库分享(包括彩云小译分享码)
热门文章
- 有源电力滤波器在地铁站低压配电系统中的应用分析
- 【公开课】印度理工学院 - CMOS射频集成电路(L3)课堂笔记
- “80后”的二代身份证该换了!
- matlab读s2p文件,s2p文件查看工具_s2p文件查看器(SPview III)下载 v3.53官方版 - 121下载站...
- 工具类-httpClient工具类
- 跟我学c++中级篇——类型擦除
- 我的世界服务器指令修复耐久,我的世界中唯一可以修复物品的工具 你知道多少?...
- GM903在线电机转子磁场波形测试仪
- Huffman 编码原理详解(代码示例)
- 史上最强像素画教程 「Pixel Art6」RPG偽遊戲畫面像素教學本