JDK源码(二十六):Timer

Posted jdkSpring

tags:

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

Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。而Timer的使用需要TimeTask类的配合,TimerTask为抽象类,需要重写类中的run方法。

TimerTask

从上面的源码上可以看出,TimerTask类是一个抽象类,其中定义了任务的各种状态及任务的锁对象,此类只有3个方法,而我们需重写其中的run方法表示我们要执行的代码。

Timer

Timer是后台线程中调度任务以供将来执行的工具。任务可以安排为一次性执行,也可以安排为定期重复执行。
对应于每个计时器对象的是一个单独的后台线程,用于按顺序执行计时器的所有任务。计时器任务应快速完成。如果计时器任务需要过多的时间来完成,它将占用计时器的任务执行线程。这反过来又会延迟后续任务的执行,当(如果)违规任务最终完成时,后续任务可能会“扎堆”并快速连续执行。
在对Timer对象的最后一次引用消失并且所有未完成的任务都已完成执行之后,计时器的任务执行线程将正常终止(并受到垃圾收集的影响)。然而,这可能需要任意长的时间才能发生。默认情况下,任务执行线程不作为守护进程线程运行,因此它能够防止应用程序终止。如果调用方希望快速终止计时器的任务执行线程,则调用方应调用计时器的cancel方法。
这个类是线程安全的:多个线程可以共享一个计时器对象,而不需要外部同步。

类名

public class Timer 

变量

JDK源码(二十六):Timer

Timer底层是把一个个任务放在TaskQueue中,TaskQueue是以平衡二进制堆表示的优先级队列,他是通过nextExecutionTime进行优先级排序的,距离下次执行时间越短优先级越高,通过getMin()获得queue[1],并且出队的时候通过synchronized保证线程安全,延迟执行和特定时间执行的底层实现类似。

schedule(TimerTask task, long delay, long period)

JDK源码(二十六):Timer

sched(TimerTask task, long time, long period)

JDK源码(二十六):Timer

下面主要来看下周期性调度通过什么方式实现的,在Timer类中TimerThread这个类实现计时器的任务执行线程,该线程等待计时器队列上的任务,在任务触发时执行它们,重新安排重复任务,并从队列中删除已取消的任务和已花费的非重复任务。TimerThread继承Thread类,在Timer类的构造方法中开启线程执行start()方法,通过mainLoop()方法实现任务调度。

实例

Timer timer = new Timer();TimerTask timerTask = new TimerTask() { @Override public void run() { HttpRequest.getZizhi(); index++; if (index > 1){ timer.cancel(); } }};timer.schedule(timerTask, 0, 2000);

schedule方法 和 scheduleAtFixedRate方法

schedule:每次执行完当前任务后,然后间隔一个period的时间再执行下一个任务,因此执行时间会不断延后。比如每次的任务执行时间为2秒,period时间为1秒,那么就相当于每3秒执行一次任务。

scheduleAtFixedRate:每次执行时间为上一次任务开始起向后推一个period间隔,也就是说下次执行时间相对于上一次任务开始的时间点,因此执行时间不会延后,但是存在任务并发执行的问题。 

并发问题:比如任务每间隔3秒执行一次,突然有一次任务执行了6秒钟,因为6秒钟可以执行两次任务,所以下次执行就会一下子执行两次该任务。

缺点

  1. 首先Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。

  2. 其次Timer线程是不会捕获异常的,如果TimerTask抛出的了未检查异常则会导致Timer线程终止,同时Timer也不会重新恢复线程的执行,他会错误的认为整个Timer线程都会取消。同时,已经被安排但尚未执行的TimerTask也不会再执行了,新的任务也不能被调度。

  3. 因为Timer底层是使用一个单线来实现多个Timer任务处理的,所有任务都是由同一个线程来调度,所有任务都是串行执行,意味着同一时间只能有一个任务得到执行,而前一个任务的延迟或者异常会影响到之后的任务。

这些缺点可以通过ScheduledExecutorService来代替

源码(1.8)

以上是关于JDK源码(二十六):Timer的主要内容,如果未能解决你的问题,请参考以下文章

android源码解析(二十六)-->截屏事件流程

Vue.js 源码分析(二十六) 高级应用 作用域插槽 详解

MATLAB实战系列(二十六)-遗传算法求解车间调度问题

企业分布式微服务云SpringCloud SpringBoot mybatis (二十六)集成apidoc

MATLAB可视化实战系列(二十六)-MATLAB非线性可视化之线性系统相图(附源码)

JDK源码(二十一):ArrayList