执行Timer任务调度方法有如下几种:

这些方法最后调用的都是这个方法:

 private void sched(TimerTask task, long time, long period)
 
这个方法的作用是将task放入Timer实例的共享变量queue(TaskQueue类型)中。源码如下:
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();
}
}
 
TaskQueue按照一个“完全二叉树堆”来进行排序,完全二叉树堆的中根节点的值最大(或者最小),每节点的值大于(或者小于)其两个子节点。
 
queue.add(task)时首先将该任务放到队列最后,会发生“上浮”动作,最终保持完全二叉树堆的根节点存放task.nextExecutionTime最小的那个task,如果要执行任务直接从TaskQueue的根节点获取那个值执行,执行完任务后从队列中移除。
 
这篇文章以图文的方式对二叉树堆算法讲解的很清晰 http://weixin.niurenqushi.com/article/2016-06-17/4326390.html,可以参考一下。
 
回到源码,sched(TimerTask task, long time, long period) 方法会将一个任务加入到TaskQueue队列后,如果这个任务在队列中的根节点(也就是nextExecutionTime最小的那个task),那就发出notify通知,激活其他占用了该任务由于wait()而阻塞状态的线程。
 
那这个线程主要涉及那一块呢?答案是Timer的线程体,源码如下:
public void run() {
try {
mainLoop();
} finally {
// Someone killed this Thread, behave as if Timer cancelled
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminate obsolete references
}
}
} /**
* The main timer loop. (See class comment.)
*/
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty,等待被notify激活
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) { // 如果period=0,则任务进行一次便结束,并移出队列
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // 设置下一次执行的时间
// task.period<0 对应 scheduleAtFixedRate 方法
// task.period>0 对应 schedule 方法
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
// 任务执行时间没到,等待,直到下一次执行时间大于当前时间
if (!taskFired)
queue.wait(executionTime - currentTime);
}
// 执行任务时间到达,开始执行任务,没有加锁,并发执行
if (taskFired) // Task fired; run it, holding no locks
task.run();
} catch(InterruptedException e) {
}
}
}

  

schedule与scheduleAtFixedRate之Timer源码分析的更多相关文章

  1. Unity时钟定时器插件——Vision Timer源码分析之二

      Unity时钟定时器插件——Vision Timer源码分析之二 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 前面的已经介绍了vp_T ...

  2. 并发编程 —— Timer 源码分析

    前言 在平时的开发中,肯定需要使用定时任务,而 Java 1.3 版本提供了一个 java.util.Timer 定时任务类.今天一起来看看这个类. 1.API 介绍 Timer 相关的有 3 个类: ...

  3. Java并发编程笔记之Timer源码分析

    timer在JDK里面,是很早的一个API了.具有延时的,并具有周期性的任务,在newScheduledThreadPool出来之前我们一般会用Timer和TimerTask来做,但是Timer存在一 ...

  4. Unity时钟定时器插件——Vision Timer源码分析之一

    因为项目中,UI的所有模块都没有MonBehaviour类(纯粹的C#类),只有像NGUI的基本组件的类是继承MonoBehaviour.因为没有继承MonoBehaviour,这也不能使用Updat ...

  5. storm定时器timer源码分析-timer.clj

    storm定时器与java.util.Timer定时器比较相似.java.util.Timer定时器实际上是个线程,定时调度所拥有的TimerTasks:storm定时器也有一个线程负责调度所拥有的& ...

  6. JUC源码分析-线程池篇(三)Timer

    JUC源码分析-线程池篇(三)Timer Timer 是 java.util 包提供的一个定时任务调度器,在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. 1. Ti ...

  7. Nimbus<二>storm启动nimbus源码分析-nimbus.clj

    nimbus是storm集群的"控制器",是storm集群的重要组成部分.我们可以通用执行bin/storm nimbus >/dev/null 2>&1 &a ...

  8. python线程threading.Timer源码解读

    threading.Timer的作用 官方给的定义是: """Call a function after a specified number of seconds: t ...

  9. [源码分析] 并行分布式任务队列 Celery 之 Timer & Heartbeat

    [源码分析] 并行分布式任务队列 Celery 之 Timer & Heartbeat 目录 [源码分析] 并行分布式任务队列 Celery 之 Timer & Heartbeat 0 ...

随机推荐

  1. decorator and @property

    @property 首先, 它是个装饰器. 其次, 看到这个东西, 意味着它下面的函数可以被当作一个属性(成员变量)来看到.  通常, 这个函数会return点什么东西. 重点讲讲装饰器: 1, py ...

  2. ffmpeg && nginx hls

    备注: 使用ffmpeg 将视频转换为hls,并使用nginx 提供服务,实现点播功能,没有使用rtmp 插件 1.  ffmpeg 命令生成文件 a. ts ffmpeg -y -i mydemo. ...

  3. 云原生应用基金会CNCF

    2006 年 8 月 9 日,埃里克·施密特(EricSchmidt)在搜索引擎大会上首次提出了“云计算”(Cloud Computing)的概念.一转眼十年过去了,它的发展势如破竹,不断渗透当代的 ...

  4. 关于ng-class,ng-style的用法

    ng-class的使用几种方式 (1):利用双向数据绑定(className根据chang2的值去匹配类) <div class="{{className}}">... ...

  5. redis数据结构对象

    redis的数据结构对象包括 字符串 列表 哈希 集合 有序集合五种数据结构对象,由底层的8种数据结构组成这五种对象,每种对象的实现不同的数据都是不一样的. 结构 typedef struct red ...

  6. python 变量 不断 相加 or 相减的简便写法 a +=1

    相加: 相减:

  7. XML的学习

    XML是可扩展标记语言德意思,它和HTML一样都是标记语言(标签语言),不同之处在于XML可拓展,何为可拓展?在HTML中每个标签都有其特定的含义,我们不可以随便写一个标签并赋予其意义,而XML中就可 ...

  8. 【洛谷】P1379 八数码难题(bfs)

    题目 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局 ...

  9. SQL Server 全文索引的硬伤

    本文关键字:SQL Server全文索引.CONTAINS.FREETEXT.CONTAINSTABLE.FREETEXTTABLE等谓词. 想象这样一个场景:在DataBase_name.dbo.T ...

  10. linux加程序是否当掉检测脚本

    cd $(dirname $) source ~/.bash_profile SYSTEM_TIME=`date '+%Y-%m-%d %T'` count=`ps -ef |grep "p ...