线程执行者(八)执行者周期性地运行一个任务
声明:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González 译者:许巧辉 校对:方腾飞
执行者周期性地运行一个任务
执行者框架提供ThreadPoolExecutor类,使用池中的线程执行并发任务,从而避免所有线程的创建操作。当你提交任务给执行者,根据它的配置,它尽快地执行任务。当它结束,任务将被执行者删除,如果你想再次运行任务,你必须再次提交任务给执行者。
但是执行者框架通过ScheduledThreadPoolExecutor类可以执行周期性任务。在这个指南中,你将学习如何通过使用这个类的功能来安排一个周期性任务。
准备工作…
这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。
如何做…
按以下步骤来实现的这个例子:
1.创建Task类,并指定它实现Runnable接口。
1
|
public class Task implements Runnable {
|
2.声明一个私有的、类型为String、名为name的属性,用来存储任务的名称。
1
|
private String name;
|
3.实现Task类的构造器,初始化name属性。
1
|
public Task(String name) {
|
2
|
this .name=name;
|
3
|
}
|
4.实现run()方法,写入实际日期到控制台,检查任务在指定的时间内执行。
1
|
@Override
|
2
|
public String call() throws Exception {
|
3
|
System.out.printf( "%s: Starting at : %s\n" ,name, new Date());
|
4
|
return "Hello, world" ;
|
5
|
}
|
5.实现示例的主类,创建Main类,实现main()方法。
1
|
public class Main {
|
2
|
public static void main(String[] args) {
|
6.使用Executors类的newScheduledThreadPool()方法,创建ScheduledThreadPoolExecutor。传入参数1给这个方法。
1
|
ScheduledExecutorService executor=Executors.newScheduledThreadPool( 1 );
|
7.写入实际日期到控制台。
1
|
System.out.printf( "Main: Starting at: %s\n" , new Date());
|
8.创建一个新的Task对象。
1
|
Task task= new Task( "Task" );
|
9.使用scheduledAtFixRate()方法把它提交给执行者。使用前面创建的任务,数字1,数字2和常量TimeUnit.SECONDS作为参数。这个方法返回ScheduledFuture对象,它可以用来控制任务的状态。
1
|
ScheduledFuture<?> result=executor.scheduleAtFixedRate(task, 1 , 2 , TimeUnit.SECONDS);
|
10.创建10个循环步骤,写入任务下次执行的剩余时间。在循环中,使用ScheduledFuture对象的getDelay()方法,获取任务下次执行的毫秒数。
01
|
for ( int i= 0 ; i< 10 ; i++){
|
02
|
System.out.printf( "Main: Delay: %d\n" ,result.
|
03
|
getDelay(TimeUnit.MILLISECONDS));
|
04
|
//线程睡眠500毫秒
|
05
|
try {
|
06
|
TimeUnit.MILLISECONDS.sleep( 500 );
|
07
|
} catch (InterruptedException e) {
|
08
|
e.printStackTrace();
|
09
|
}
|
10
|
}
|
11.使用shutdown()方法关闭执行者。
1
|
executor.shutdown();
|
12.使线程睡眠5秒,检查周期性任务是否完成。
1
|
try {
|
2
|
TimeUnit.SECONDS.sleep( 5 );
|
3
|
} catch (InterruptedException e) {
|
4
|
e.printStackTrace();
|
5
|
}
|
13.写入一条信息到控制台,表明程序结束。
1
|
System.out.printf( "Main: Finished at: %s\n" , new Date());
|
它是如何工作的…
当你想要使用执行者框架执行一个周期性任务,你需要ScheduledExecutorService对象。Java建议使用 Executors类创建执行者,Executors类是一个执行者对象工厂。在本例中,你应该使用newScheduledThreadPool()方法,创建一个 ScheduledExecutorService对象。这个方法接收池的线程数作为参数。正如在本例中你只有一个任务,你传入了值1作为参数。
一旦你有执行者需要执行一个周期性任务,你提交任务给该执行者。你已经使用了scheduledAtFixedRate()方法。此方法接收4个参数:你想要周期性执行的任务、第一次执行任务的延迟时间、两次执行之间的间隔期间、第2、3个参数的时间单位。它是TimeUnit类的常 量,TimeUnit类是个枚举类,有如下常量:DAYS,HOURS,MICROSECONDS, MILLISECONDS, MINUTES,,NANOSECONDS 和SECONDS。
很重要的一点需要考虑的是两次执行之间的(间隔)期间,是这两个执行开始之间的一段时间。如果你有一个花5秒执行的周期性任务,而你给一段3秒时间,同一时刻,你将会有两个任务在执行。
scheduleAtFixedRate() 方法返回ScheduledFuture对象,它继承Future接口,这个方法和调度任务一起协同工作。ScheduledFuture是一个参数化接口(校对注:ScheduledFuture<V>)。在这个示例中,由于你的任务是非参数化的Runnable对象,你必须使用 问号作为参数。
你已经使用ScheduledFuture接口的一个方法。getDelay()方法返回直到任务的下次执行时间。这个方法接收一个TimeUnit常量,这是你想要接收结果的时间单位。
以下截图显示这个示例执行的输出:
你可以看出用Task:作为前缀的任务每2秒执行一次,并且每演示500毫秒向控制台写入一次。这就是main线程睡眠的时间。当你关闭执行者,这个计划任务结束它的执行,你将不会在控制台看到更多的信息。
不止这些…
ScheduledThreadPoolExecutor 提供其他方法来调度周期性任务。这就是scheduleWithFixedRate()方法。它与scheduledAtFixedRate()方法有一 样的参数,但它们之间的差异值得注意。在scheduledAtFixedRate()方法中,第3个参数决定两个执行开始的一段时间。在 scheduledWithFixedRate()方法中,参数决定任务执行结束与下次执行开始之间的一段时间。
当你使用 shutdown()方法时,你也可以通过参数配置一个SeduledThreadPoolExecutor的行为。shutdown()方法默认的行为是,当你调用这个方法时,计划任务就结束。 你可以使用ScheduledThreadPoolExecutor类的 setContinueExistingPeriodicTasksAfterShutdownPolicy()方法设置true值改变这个行为。在调用 shutdown()方法时,周期性任务将不会结束。
参见
- 在第4章,线程执行者中的创建一个线程执行者食谱
- 在第4章,线程执行者中的执行者延迟运行一个任务食谱
- 文章转自 并发编程网-ifeve.com
线程执行者(八)执行者周期性地运行一个任务相关推荐
- JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理...
本文记录: 1,使用ScheduledExecutorService的 scheduleAtFixedRate 方法执行周期性任务的过程,讨论了在任务周期执行过程中出现了异常,会导致周期任务失败. 2 ...
- JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理
JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理 参考文章: (1)JAVA线程池ScheduledExecutorServi ...
- 从青铜到王者,Python 实现定时任务的八种方案,最后一个是神级!
作者:钱魏Way https://www.biaodianfu.com/python-schedule.html 在日常工作中,我们常常会用到需要周期性执行的任务,一种方式是采用 Linux 系统自带 ...
- 线程知识点(一)—— 程序、进程、线程之间的区别与联系、Java的线程状态和生命周期
1 程序.进程.线程之间的区别与联系 三者之间的形象化理解: * 程序:代码实现了功能,就是程序,是静态的: * 进程:执行中的程序就是进程,是动态的: * 线程:进程内的一个执行单元,也是进程内的可 ...
- 【嵌入式系统开发15】STM32F103C8T6下通过定时器Timer方式实现时间的精准控制,实现串口通信并让LED等周期性地闪烁
本文目的是主要介绍通过STM32F103C8T6采用定时器Timer方式实现时间的精准控制,相当于给CPU上了一个闹钟,CPU平时处理其它任务,当定时时间到了以后,处理定时相关的任务.请设置一个5秒的 ...
- 为什么建议一个容器中只运行一个进程
文章首发于:https://www.cnblogs.com/JasonCeng/p/14814888.html 在云原生与容器化时代浪潮下,大多数新手的普遍认识是"容器=虚拟机", ...
- 使用 sched_setaffinity 将线程绑到CPU核上运行
linux 提供CPU调度函数,可以将CPU某一个核和指定的线程绑定到一块运行. 这样能够充分利用CPU,且减少了不同CPU核之间的切换,尤其是在IO密集型压力之下能够提供较为友好的性能. 通过sch ...
- Podman中如何运行一个 Linux 虚拟机?
使用 Podman Machine 创建一个基本的 Fedora CoreOS 虚拟机来使用容器和容器化工作负载. Fedora CoreOS 是一个自动更新.最小化的基于 rpm-ostree 的操 ...
- Python 安装 uWSGI并运行一个入门示例
Python 安装 uWSGI 1.通过 pip 命令: pip install uwsgi 2.下载安装脚本: curl http://uwsgi.it/install | bash -s defa ...
- HDFS设计思路,HDFS使用,查看集群状态,HDFS,HDFS上传文件,HDFS下载文件,yarn web管理界面信息查看,运行一个mapreduce程序,mapreduce的demo
26 集群使用初步 HDFS的设计思路 l 设计思想 分而治之:将大文件.大批量文件,分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析: l 在大数据系统中作用: 为各类分布式 ...
最新文章
- 如何起一个好的学术期刊论文题目?
- (33)调试驱动程序
- python3精要(27)-*与**解包
- 设计包含min()函数的栈
- 第五章functions.py中的交叉熵代码解释
- java map集合排序的_Java对Map集合进行排序
- Python学习笔记:微积分计算
- 服务器系统安装及部署pdf,服务器操作系统安装说明.pdf
- spark python教程_spark2.x由浅入深深到底系列七之python开发spark环境配置
- 《Linux命令行与shell脚本编程大全 第3版》高级Shell脚本编程---35
- 20191221每日一句
- IPTV软件提取后无法安装:显示安装失败,需求的共享用户签名错误!请大神帮助,谢谢
- mac电脑用计算机名共享打印机,苹果电脑怎么连接共享打印机_苹果电脑连接共享打印机的具体教程-系统城...
- SSL Virtual Private Network的技术分析
- Online Convex Making Gradient Descent Optimal for Strongly Convex Stochastic Optimization
- Excel条形图更换顺序
- keras自然语言处理(五)
- 数字图像处理与python实现-带通滤波器
- 用计算机来打字学猫叫,电脑打字轻松技巧 怎么联系快速打字
- 数字图像处理 离散图象变换
热门文章
- 联调测试是什么意思_阿里开源 KT Connnect,轻量级云原生测试环境治理平台来啦!...
- java动画帧储存路径_Java实现帧动画的实例代码
- 个推的appid是指什么_私人教练要注意胸肌更快增厚的4个方法
- 加密能抓到吗?怎么抓_网络赌博被抓怎么处罚 网上参与赌博会坐牢吗
- python导入自己写的包_python的模块,包和目录的区别和自定义包的注意点
- 数据采集无线网服务器软件,WIFI智能数据盒
- 一个网站哪些页面需要用到redis_网页和网站有什么区别?做一个网站难不难?都需要哪些技能?...
- 帆软扩展单元格运算的相关应用
- Python转换图片格式 -- PIL库的使用
- Algs4-1.1.6下面这段程序会打印出什么