工作中常常会有定时任务的开发需求,特别是移动端。最近笔者正好有所涉及,鉴于此,结合开发中的案例说明一下几种定时任务的退出。

需求说明:定时更新正在生成的文件大小和状态【进行中、失败、完成】,如果文件生成完成,则退出【CoderBaby

调度这可以用Timer 【可以调用schedule()或者scheduleAtFixedRate()方法实现】或者ScheduledExecutorService   【结合工作中其它的需求,笔者选用此】

ScheduledExecutorService的初始化(线程池):

private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
  • 自己手动实现——最朴素的方案【通过sleep来控制时间间隔、break来退出】
            scheduledExecutorService.execute(() -> {
long oldCurFileSize = 0;
while(true) {
try {
Thread.sleep(updateInternal * 1000);
long curFileSize = Files.size(Paths.get(TMP_PCAP_PATH + tmpPcapFileName));
int status = getStatus(tmpPcapFileName);
if (isFailed(status) || hasNoData(status) || isFinished(status)) {
break;
}
if (curFileSize != oldCurFileSize) {
updateFileInfo(tmpPcapFileName, curFileSize, 0);
oldCurFileSize = curFileSize;
} else {
updateFileInfo(tmpPcapFileName, curFileSize, 3);
// 延迟1秒,才能成功更新
Thread.sleep(1000);
break;
}
} catch (Exception e) {
logger.warn("Catch exception : " + e.toString());
}
}
});

注:

updateFileInfo—更新数据库相关记录;

getStatus查询数据库当前记录的状态,判定是否完成或者出现错误;

updateInternal控制定时任务的运行时间间隔(单位为秒)

  • TimerTask【通过cancel来退出】

定义一个内部类继承TimerTask抽象类

    class ScheduledUpdateTrafficForensics extends TimerTask {
private String tmpPcapFileName;
private long oldCurrentFileSize = 0; public ScheduledUpdateTrafficForensics(String tmpPcapFileName) {
this.tmpPcapFileName = tmpPcapFileName;
} public void run() {
try {
long currentFileSize = Files.size(Paths.get(TMP_PCAP_PATH + tmpPcapFileName));
int status = getStatus(tmpPcapFileName);
if (isFailed(status) || hasNoData(status) || isFinished(status)) {
this.cancel();
}
if (oldCurrentFileSize != currentFileSize) {
updateFileInfo(tmpPcapFileName, currentFileSize, 0);
} else {
updateFileInfo(tmpPcapFileName, currentFileSize, 3);
this.cancel();
}
} catch (IOException e) {
logger.warn("Catch exception : " + e.toString());
}
}
}

通过scheduleAtFixedRate接口来调用(设置时间间隔和且第一次执行的延迟时间)

            scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(new ScheduledUpdateTrafficForensics(tmpPcapFileName),
updateInternal, pcapDownloadStatusUpdateInternal, TimeUnit.SECONDS);
  • ScheduledFuture【通过cancle来退出】

定义一个内部类继承Runnable接口

     class ScheduledUpdateTrafficForensics implements Runnable {
private String tmpPcapFileName;
private long oldCurrentFileSize = 0; public ScheduledUpdateTrafficForensics(String tmpPcapFileName) {
this.tmpPcapFileName = tmpPcapFileName;
} public void run() {
while (!scheduledFuture.isCancelled()) {
try {
long currentFileSize = Files.size(Paths.get(TMP_PCAP_PATH + tmpPcapFileName));
int status = getStatus(tmpPcapFileName);
if (isFailed(status) || hasNoData(status)) {
scheduledFuture.cancel(true);
return;
}
if (!isFinished(status)) {
updateFileInfo(tmpPcapFileName, currentFileSize, 0);
}
} catch (IOException e) {
logger.warn("Catch exception : " + e.toString());
}
}
}
}

通过scheduleAtFixedRate接口来调用(设置时间间隔和且第一次执行的延迟时间),并且将结果返回给ScheduledFuture

            scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(new ScheduledUpdateTrafficForensics(tmpPcapFileName),
updateInternal, pcapDownloadStatusUpdateInternal, TimeUnit.SECONDS);

注:通过scheduledFuture.cancel(true)后可能不能成功结束定时任务,所以必须通过手动调用isCancelled()来判断是否被cancle(调用cancel后,再调用isCancelled() 【一定会返回true】)掉了,然后退出任务。相关源码注释如下:

     * <p>After this method returns, subsequent calls to {@link #isDone} will
* always return {@code true}. Subsequent calls to {@link #isCancelled}
* will always return {@code true} if this method returned {@code true}.

特别说明:

关于schedule(时间基准:运行的实际时间)和scheduleAtFixedRate(时间基准:理论时间点)的区别:

  • scheduleAtFixedRate调度一个task,在delay(ms)后开始调度,然后每经过period(ms)再次调度,貌似和方法—schedule是一样的,其实不然。
  • schedule在计算下一次执行的时间的时候,是通过当前时间(在任务执行前得到) + 时间片,而scheduleAtFixedRate方法是通过当前需要执行的时间(也就是计算出现在应该执行的时间)+ 时间片,前者是运行的实际时间,而后者是理论时间点。

例如:schedule时间片是5s,那么理论上会在5、10、15、20这些时间片被调度,但是如果由于某些CPU征用导致未被调度,假如等到第8s才被第一次调度,那么schedule方法计算出来的下一次时间应该是第13s而不是第10s,这样有可能下次就越到20s后而被少调度一次或多次,而scheduleAtFixedRate方法就是每次理论计算出下一次需要调度的时间用以排序,若第8s被调度,那么计算出应该是第10s,所以它距离当前时间是2s,那么再调度队列排序中,会被优先调度,那么就尽量减少漏掉调度的情况。

详情请移步https://www.cnblogs.com/dolphin0520/p/3938991.html

*********************************************************************************

精力有限,想法太多,专注做好一件事就行

  • 我只是一个程序猿。5年内把代码写好,技术博客字字推敲,坚持零拷贝和原创
  • 写博客的意义在于锻炼逻辑条理性,加深对知识的系统性理解,锻炼文笔,如果恰好又对别人有点帮助,那真是一件令人开心的事

*********************************************************************************

几种定时任务(Timer、TimerTask、ScheduledFuture)的退出—结合真实案例【JAVA】的更多相关文章

  1. 服务器启动完成执行定时任务Timer,TimerTask

    由于项目需求:每隔一段时间就要调外部接口去进行某些操作,于是在网上找了一些资料,用了半天时间弄好了,代码: import java.util.TimerTask; public class Accou ...

  2. Android 中执行定时任务 Timer + TimerTask

    1. new Timer().schedule(new TimerTask() { @Override public void run() { //任务代码 } }, 0, 5000);

  3. Spring boot 集成三种定时任务方式

    三种定时任务方式分别为 org.springframework.scheduling.annotation.Scheduled java.util.concurrent.ScheduledExecut ...

  4. 线程 Timer TimerTask 计时器 定时任务 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  5. Timer&TimerTask原理分析

    转载地址,请珍惜作者的劳动成果,转载请注明出处:http://www.open-open.com/lib/view/open1337176725619.html 如果你使用Java语言进行开发,对于定 ...

  6. 详解java定时任务---Timer篇

    一.简介      在java的jdk中提供了Timer.TimerTask两个类来做定时任务. Timer是一种定时器工具,用来在一个后台线程计划执行指定任务,而TimerTask一个抽象类,它的子 ...

  7. Java之旅--定时任务(Timer、Quartz、Spring、LinuxCron)

    在Java中,实现定时任务有多种方式,本文介绍4种,Timer和TimerTask.Spring.QuartZ.Linux Cron. 以上4种实现定时任务的方式,Timer是最简单的,不需要任何框架 ...

  8. java目前常用的几种定时任务

    java目前常用的几种定时任务 JDK自带的Timer spring的Task Quartz elastic-job分布式定时任务 一.JDK自带的Timer Timer是jdk中提供的一个定时器工具 ...

  9. 【SpringBoot】几种定时任务的实现方式

    SpringBoot 几种定时任务的实现方式 Wan QingHua 架构之路  定时任务实现的几种方式: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java ...

随机推荐

  1. mysql 5.7.13 安装配置方法

    linux环境Mysql 5.7.13安装教程分享给大家,供大家参考,具体内容如下: 1系统约定 安装文件下载目录:/data/software Mysql目录安装位置:/usr/local/mysq ...

  2. 大数据框架Hive优化方法

    常规调优手段 Fetch抓取 某些情况查询不必用MapReduce计算,比如select*,可以直接读取文件 本地模式 有时数据量比较小,hive可以通过本地模式在单台机器上处理所有任务,对于小数据集 ...

  3. laravel5.5 安装

    环境要求 PHP >= 7.0.0 PHP OpenSSL 扩展 PHP PDO 扩展 PHP Mbstring 扩展 PHP Tokenizer 扩展 PHP XML 扩展 通过 Larave ...

  4. Qt自定义控件之仪表盘1--简单的贴图仪表盘

    0.前言 学程序首先要输出hell world,学电子要先来个流水灯.学Qt,那就必须先来个自定义控件,若有人问我从哪个下手,我推荐仪表盘,可简可繁,从低配到高配齐全,可入门也可进阶. 1.仪表盘解析 ...

  5. 使用MacOS直播

    参考链接:https://www.jianshu.com/p/94f42a793a7e 参考链接:https://blog.dreamtobe.cn/live_guideline/ 所需软件  密码: ...

  6. Python 字典(Dictionary) type()方法

    Python 字典(Dictionary) type()方法 描述 Python 字典(Dictionary) type() 函数返回输入的变量类型,如果变量是字典就返回字典类型.高佣联盟 www.c ...

  7. mit-6.828 Lab Tools

    Lab Tools 目录 Lab Tools 写在前面 GDB GNU GPL (通用公共许可证) QEMU ELF 可执行文件的格式 Verbose mode Makefile 写在前面 操作系统小 ...

  8. 数据结构C语言实现----选择排序

    选择排序 第一步:从一串无序数字串中选一个最小的与第一个数交换位置 第二步:从剩下的数字中选一个最小的与第二个数交换位置 第三步:从剩下的数字中选一个最小的与第三个数字交换位置 以此类推... 运行结 ...

  9. 【原创】xenomai与VxWorks实时性对比(资源抢占上下文切换对比)

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有问题,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ (下面数据,仅供个人参考) 可能大部分人一直好奇Vx ...

  10. 使用Flask开发简单接口(5)--数据加密处理

    前言 在之前开发的接口中,我们设计把用户信息存储到数据库时,没有对数据进行加密处理,为了提高下安全性,我们今天就学习下,如何对用户数据进行加密加盐处理. MD5加密加盐 MD5加密 MD5是常用的一种 ...