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

需求说明:定时更新正在生成的文件大小和状态【进行中、失败、完成】,如果文件生成完成,则退出【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. 分布式锁(2) ----- 基于redis的分布式锁

    分布式锁系列文章 分布式锁(1) ----- 介绍和基于数据库的分布式锁 分布式锁(2) ----- 基于redis的分布式锁 分布式锁(3) ----- 基于zookeeper的分布式锁 代码:ht ...

  2. class初探

    我们说类的时候,先回忆一下es5的构造函数 function myobj(x,y){ this.x= x; this.y =y; } myobj.prototype.add = function(){ ...

  3. Git日常操作指南

    git status git add . git commit -m "注释" git stash # 每次 push 前 git pull --rebase // 如果有冲突,解 ...

  4. URI(统一资源标识符)

    URI:统一资源标识符 (Uniform Resource Identifier) 统一资源标识符是一个用于标识某一互联网资源名称的字符串. Web上可用的每种资源 -HTML文档.图像.视频片段.程 ...

  5. 报错:invalid operands to binary - (have ‘int’ and ‘char *’)

    //这个题是输入大写的一串字符,然后按A对应1...这个规律求乘积 char a[],b[]; scanf("%s",a); scanf("%s",b); in ...

  6. 【JMicro】微服务部署example.provider应用

    JMicro是一个用Java语言实现的开源微服务全家桶, 源码地址:https://github.com/mynewworldyyl/jmicro, Demo地址:http://124.70.152. ...

  7. Django学习路3

    1.打开 Data Source alt insert 打开 Data Source 找到 db.sqlite3 确定 Download 下载后 TestConnection 测试是否成功 2.项目下 ...

  8. PHP empty() 函数

    empty() 函数用于检查一个变量是否为空.高佣联盟 www.cgewang.com empty() 判断一个变量是否被认为是空的.当一个变量并不存在,或者它的值等同于 FALSE,那么它会被认为不 ...

  9. PHP xml_parser_get_option() 函数

    定义和用法 xml_parser_get_option() 函数从 XML 解析器获取选项.高佣联盟 www.cgewang.com 如果成功,该函数则返回选项值.如果失败,则返回 FALSE 和一个 ...

  10. Blob分析之 ball.hdev

    * ball.hdev: Inspection of Ball Bonding * 关闭窗体更新 dev_update_window ('off')*关闭窗体dev_close_window ()*打 ...