Timer的源码分析
2015-12-19 21:54
344 查看
对java Timer的分析
为什么要分析Timer的源码进行分析?
希望对Timer类的了解,加深对任务调度的理解。Timer源码的分析
public void schedule(TimerTask task, long delay);//经过特定的时间执行 public void schedule(TimerTask task, Date time);//在特定的时间运行 public void schedule(TimerTask task, long delay, long period);//每经过特定的时间再次运行 public void schedule(TimerTask task, Date firstTime, long period); public void scheduleAtFixedRate(TimerTask task, long delay, long period);//也是经过特定的时间进行运行。
这是Timer的基本用法。
上面的方法都会调用
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException(“Illegal execution time.”);
// Constrain value of period sufficiently to prevent numeric // overflow while still being effectively infinitely large. if (Math.abs(period) > (Long.MAX_VALUE >> 1)) period >>= 1; synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled."); synchronized(task.lock) { if (task.state != TimerTask.VIRGIN) throw new IllegalStateException( "Task already scheduled or cancelled"); task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; } queue.add(task); if (queue.getMin() == task) queue.notify(); } }
我们可以看到为了线程安全,首先对queue进行了锁定,然后设置了task下一次的执行时间,以及周期。
那么queue添加task会发生什么事情呢?TaskQueue是一个以执行时间排序的二叉树,距离执行时间最短的越在上面。Timer在初始化的时候会初始化一个TimerThread,并且start它。在run()里面会进行调用mainLoop(),而mainLoop()如下面代码所示:
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
if (queue.isEmpty())
break; // Queue is empty and will forever remain; die
// Queue nonempty; look at first evt and do the right thing long currentTime, executionTime; task = queue.getMin(); synchronized(task.lock) { if (task.state == TimerTask.CANCELLED) { queue.removeMin(); continue; // No action required, poll queue again } currentTime = System.currentTimeMillis(); executionTime = task.nextExecutionTime; if (taskFired = (executionTime<=currentTime)) { if (task.period == 0) { // Non-repeating, remove queue.removeMin(); task.state = TimerTask.EXECUTED; } else { // Repeating task, reschedule queue.rescheduleMin( task.period<0 ? currentTime - task.period : executionTime + task.period); } } } if (!taskFired) // Task hasn't yet fired; wait queue.wait(executionTime - currentTime); } if (taskFired) // Task fired; run it, holding no locks task.run(); } catch(InterruptedException e) { } } }
当获取queue的锁以后,首先我们会判断是否为空,如果为空的话,我们就会等待。然后我们会判断是否到了该执行的时间,如果不是则等待,否则执行。执行的过程中,需要判断是否是否一次性执行的任务,如果是直接从queue中剔除掉,如果不是则需要重新将task添加到queue中,至于为什么需要判断task.period小于0,则是为了区别 public void schedule(TimerTask task, long delay)以及 public void scheduleAtFixedRate(TimerTask task, long delay, long period);这两种任务,AtFixedReate意味着每次都是在特定的时间点执行,与上一次的执行时间无关。而schedule类型的任务下一次的执行时间为本次任务的执行时间点+delay,意味着本次任务的执行与上次的执行有关
注意点:
1. 在某一个Task抛出异常后,那么整个Timer就会停止。
相关文章推荐
- processing-MySQL learning4-call procedure:call proce(parameters)
- 字符串读入汇总
- springMVC和spring各自扫描自己的注解不要相互混淆
- c结构体初始化问题
- Unity EditorWindow自定义弹出窗口
- 数组去重
- C#接口和抽象类
- mysql的安装及一些常见的问题
- 16周——项目一:置换-选择算法模拟
- TextView波浪加载效果
- 【J】BaseAdapter的使用与优化
- 事务的并发控制big picture
- 一些想说的话,无关技术
- win7旗舰版(64位)环境下oracle11g的安装方法
- Office Visio简介
- MFC 填充系统 方法记录
- c++静态成员与静态函数
- putty 如何退出鼠标选中状态
- hdoj--1312--Red and Black(dfs)
- 开发该选择Blocks还是Delegates