Timer与ScheduledThreadPoolExecutor

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Timer与ScheduledThreadPoolExecutor相关的知识,希望对你有一定的参考价值。

自JDK1.5开始,JDK提供了ScheduledThreadPoolExecutor类来支持周期性任务的调度。在这之前的实现需要依靠Timer和TimerTask或者其它第三方工具来完成。但Timer有不少的缺陷:

  • Timer是单线程模式;

  • 如果在执行任务期间某个TimerTask耗时较久,那么就会影响其它任务的调度;

  • Timer的任务调度是基于绝对时间的,对系统时间敏感;

  • Timer不会捕获执行TimerTask时所抛出的异常,由于Timer是单线程,所以一旦出现异常,则线程就会终止,其他任务也得不到执行。

ScheduledThreadPoolExecutor继承ThreadPoolExecutor来重用线程池的功能,它的实现方式如下:

  • 将任务封装成ScheduledFutureTask对象,ScheduledFutureTask基于相对时间,不受系统时间的改变所影响;

  • ScheduledFutureTask实现了java.lang.Comparable接口和java.util.concurrent.Delayed接口,所以有两个重要的方法:compareTo和getDelay。compareTo方法用于比较任务之间的优先级关系,如果距离下次执行的时间间隔较短,则优先级高;getDelay方法用于返回距离下次任务执行时间的时间间隔;

  • ScheduledThreadPoolExecutor定义了一个DelayedWorkQueue,它是一个有序队列,会通过每个任务按照距离下次执行时间间隔的大小来排序;

  • ScheduledFutureTask继承自FutureTask,可以通过返回Future对象来获取执行的结果。

通过如上的介绍,可以对比一下Timer和ScheduledThreadPoolExecutor:

TimerScheduledThreadPoolExecutor
单线程多线程
单个任务执行时间影响其他任务调度多线程,不会影响
基于绝对时间基于相对时间
一旦执行任务出现异常不会捕获,其他任务得不到执行多线程,单个任务的执行不会影响其他线程

所以,在JDK1.5之后,应该没什么理由继续使用Timer进行任务调度了。

ScheduledThreadPoolExecutor实现分析:

该线程池与普通的ThreadPoolExecutor类似 就是阻塞队列用了DelayedWorkQueue,这种队列就是利用了最小堆的存储结构对任务进行存放。schedule方法类似submit方法,将任务提交,同时设置delay时间和单位还有周期等,当然这个类也提供submit和execute。放在最小堆顶端的节点是delay最小的任务,也就是每当worker从队列中取出第一个任务都是delay最小的任务,然后查看他的delay值,通过condition.awaitNanos方法阻塞线程到delay时间,等待delay时间后worker才开始执行那个任务。

以上是关于Timer与ScheduledThreadPoolExecutor的主要内容,如果未能解决你的问题,请参考以下文章

Flink - Timer 与 TimerService 源码分析与详解

System.Timers.Timer 与 System.Threading.Timer

iOS 中 self.timer = nil 与 [self.timer invalidate] 有啥区别?

Timer与ScheduledThreadPoolExecutor

简述System.Windows.Forms.Timer 与System.Timers.Timer用法区别

ScheduledThreadPoolExecutor与Timer