声明:本文是《 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,12, 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

线程执行者(八)执行者周期性地运行一个任务相关推荐

  1. JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理...

    本文记录: 1,使用ScheduledExecutorService的 scheduleAtFixedRate 方法执行周期性任务的过程,讨论了在任务周期执行过程中出现了异常,会导致周期任务失败. 2 ...

  2. JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理

    JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理 参考文章: (1)JAVA线程池ScheduledExecutorServi ...

  3. 从青铜到王者,Python 实现定时任务的八种方案,最后一个是神级!

    作者:钱魏Way https://www.biaodianfu.com/python-schedule.html 在日常工作中,我们常常会用到需要周期性执行的任务,一种方式是采用 Linux 系统自带 ...

  4. 线程知识点(一)—— 程序、进程、线程之间的区别与联系、Java的线程状态和生命周期

    1 程序.进程.线程之间的区别与联系 三者之间的形象化理解: * 程序:代码实现了功能,就是程序,是静态的: * 进程:执行中的程序就是进程,是动态的: * 线程:进程内的一个执行单元,也是进程内的可 ...

  5. 【嵌入式系统开发15】STM32F103C8T6下通过定时器Timer方式实现时间的精准控制,实现串口通信并让LED等周期性地闪烁

    本文目的是主要介绍通过STM32F103C8T6采用定时器Timer方式实现时间的精准控制,相当于给CPU上了一个闹钟,CPU平时处理其它任务,当定时时间到了以后,处理定时相关的任务.请设置一个5秒的 ...

  6. 为什么建议一个容器中只运行一个进程

    文章首发于:https://www.cnblogs.com/JasonCeng/p/14814888.html 在云原生与容器化时代浪潮下,大多数新手的普遍认识是"容器=虚拟机", ...

  7. 使用 sched_setaffinity 将线程绑到CPU核上运行

    linux 提供CPU调度函数,可以将CPU某一个核和指定的线程绑定到一块运行. 这样能够充分利用CPU,且减少了不同CPU核之间的切换,尤其是在IO密集型压力之下能够提供较为友好的性能. 通过sch ...

  8. Podman中如何运行一个 Linux 虚拟机?

    使用 Podman Machine 创建一个基本的 Fedora CoreOS 虚拟机来使用容器和容器化工作负载. Fedora CoreOS 是一个自动更新.最小化的基于 rpm-ostree 的操 ...

  9. Python 安装 uWSGI并运行一个入门示例

    Python 安装 uWSGI 1.通过 pip 命令: pip install uwsgi 2.下载安装脚本: curl http://uwsgi.it/install | bash -s defa ...

  10. HDFS设计思路,HDFS使用,查看集群状态,HDFS,HDFS上传文件,HDFS下载文件,yarn web管理界面信息查看,运行一个mapreduce程序,mapreduce的demo

    26 集群使用初步 HDFS的设计思路 l 设计思想 分而治之:将大文件.大批量文件,分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析: l 在大数据系统中作用: 为各类分布式 ...

最新文章

  1. 如何起一个好的学术期刊论文题目?
  2. (33)调试驱动程序
  3. python3精要(27)-*与**解包
  4. 设计包含min()函数的栈
  5. 第五章functions.py中的交叉熵代码解释
  6. java map集合排序的_Java对Map集合进行排序
  7. Python学习笔记:微积分计算
  8. 服务器系统安装及部署pdf,服务器操作系统安装说明.pdf
  9. spark python教程_spark2.x由浅入深深到底系列七之python开发spark环境配置
  10. 《Linux命令行与shell脚本编程大全 第3版》高级Shell脚本编程---35
  11. 20191221每日一句
  12. IPTV软件提取后无法安装:显示安装失败,需求的共享用户签名错误!请大神帮助,谢谢
  13. mac电脑用计算机名共享打印机,苹果电脑怎么连接共享打印机_苹果电脑连接共享打印机的具体教程-系统城...
  14. SSL Virtual Private Network的技术分析
  15. Online Convex Making Gradient Descent Optimal for Strongly Convex Stochastic Optimization
  16. Excel条形图更换顺序
  17. keras自然语言处理(五)
  18. 数字图像处理与python实现-带通滤波器
  19. 用计算机来打字学猫叫,电脑打字轻松技巧 怎么联系快速打字
  20. 数字图像处理 离散图象变换

热门文章

  1. 联调测试是什么意思_阿里开源 KT Connnect,轻量级云原生测试环境治理平台来啦!...
  2. java动画帧储存路径_Java实现帧动画的实例代码
  3. 个推的appid是指什么_私人教练要注意胸肌更快增厚的4个方法
  4. 加密能抓到吗?怎么抓_网络赌博被抓怎么处罚 网上参与赌博会坐牢吗
  5. python导入自己写的包_python的模块,包和目录的区别和自定义包的注意点
  6. 数据采集无线网服务器软件,WIFI智能数据盒
  7. 一个网站哪些页面需要用到redis_网页和网站有什么区别?做一个网站难不难?都需要哪些技能?...
  8. 帆软扩展单元格运算的相关应用
  9. Python转换图片格式 -- PIL库的使用
  10. Algs4-1.1.6下面这段程序会打印出什么