java scheduledfuture_几种定时任务(Timer、TimerTask、ScheduledFuture)的退出—结合真实案例【JAVA并发】...

af62cad5c009b04d122e4566e5c60a78.png

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

需求说明:定时更新正在生成的文件大小和状态【进行中、失败、完成】,如果文件生成完成,则退出【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 extendsTimerTask {privateString tmpPcapFileName;private long oldCurrentFileSize = 0;publicScheduledUpdateTrafficForensics(String tmpPcapFileName) {this.tmpPcapFileName =tmpPcapFileName;

}public voidrun() {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);

oldCurrentFileSize = currentFileSize;

}else{

updateFileInfo(tmpPcapFileName, currentFileSize,3);this.cancel();

}

}catch(IOException e) {

logger.warn("Catch exception : " +e.toString());

}

}

}

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

scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(newScheduledUpdateTrafficForensics(tmpPcapFileName),

updateInternal, pcapDownloadStatusUpdateInternal, TimeUnit.SECONDS);

ScheduledFuture【通过cancle和读取isCancelled结果来退出】

定义一个内部类实现Runnable接口

class ScheduledUpdateTrafficForensics implementsRunnable {privateString tmpPcapFileName;private long oldCurrentFileSize = 0;publicScheduledUpdateTrafficForensics(String tmpPcapFileName) {this.tmpPcapFileName =tmpPcapFileName;

}public voidrun() {while (!scheduledFuture.isCancelled()) {try{long currentFileSize = Files.size(Paths.get(TMP_PCAP_PATH +tmpPcapFileName));int status =getStatus(tmpPcapFileName);if (isFailed(status) ||hasNoData(status) || isFinished(status) {

scheduledFuture.cancel(true);return;

}if (oldCurrentFileSize != currentFileSzie) {

updateFileInfo(tmpPcapFileName, currentFileSize,0);

oldCurrentFileSize = currentFileSize;

} else {

updateFileInfo(tmpPacpFileName, currentFileSize, 3);

scheduleFuture.canle(true);

}

}catch(IOException e) {

logger.warn("Catch exception : " +e.toString());

}

}

}

}

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

scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(newScheduledUpdateTrafficForensics(tmpPcapFileName),

updateInternal, pcapDownloadStatusUpdateInternal, TimeUnit.SECONDS);

注:

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

*

After thismethod 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,那么再调度队列排序中,会被优先调度,那么就尽量减少漏掉调度的情况。

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

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

我只是一个程序猿。5年内把代码写好,技术博客字字推敲,坚持零拷贝和原创

写博客的意义在于锻炼逻辑条理性,加深对知识的系统性理解,锻炼文笔,如果恰好又对别人有点帮助,那真是一件令人开心的事

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值