【源代码】Timer和TimerTask源代码剖析
Timer是java.util包中的一个工具类,提供了定时器的功能。
我们能够构造一个Timer对象,然后调用其schedule方法在某个特定的时间或者若干延时之后去运行一个特定的任务。甚至你能够让其以特定频率一直运行某个任务,这个任务用TimerTask描写叙述,我们将须要的操作写在TimerTask类的run方法中就可以。
打开Timer类的源代码我发现了这样两个成员变量:
- /**
- * The timer task queue. This data structure is shared with the timer
- * thread. The timer produces tasks, via its various schedule calls,
- * and the timer thread consumes, executing timer tasks as appropriate,
- * and removing them from the queue when they're obsolete.
- */
- private final TaskQueue queue = new TaskQueue();//任务队列
- /**
- * The timer thread.
- */
- private final TimerThread thread = new TimerThread(queue);//运行线程
(跟android中的Handler机制非常类似~)
- class TaskQueue {
- /**
- * Priority queue represented as a balanced binary heap: the two children
- * of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is
- * ordered on the nextExecutionTime field: The TimerTask with the lowest
- * nextExecutionTime is in queue[1] (assuming the queue is nonempty). For
- * each node n in the heap, and each descendant of n, d,
- * n.nextExecutionTime <= d.nextExecutionTime.
- */
- private TimerTask[] queue = new TimerTask[128];//使用数组存储堆元素,最大值128
- /**
- * The number of tasks in the priority queue. (The tasks are stored in
- * queue[1] up to queue[size]).
- */
- private int size = 0;//任务数
- /**
- * Returns the number of tasks currently on the queue.
- */
- int size() {
- return size;
- }
- /**
- * Adds a new task to the priority queue.
- */
- void add(TimerTask task) {//将TimerTask任务加入到此队列中
- // Grow backing store if necessary
- if (size + 1 == queue.length)
- queue = Arrays.copyOf(queue, 2*queue.length);
- queue[++size] = task;
- fixUp(size);//调整堆结构---->所谓的上滤
- }
- /**
- * Return the "head task" of the priority queue. (The head task is an
- * task with the lowest nextExecutionTime.)
- */
- TimerTask getMin() {//优先级最高的元素始终在第一个位置
- return queue[1];
- }
- /**
- * Return the ith task in the priority queue, where i ranges from 1 (the
- * head task, which is returned by getMin) to the number of tasks on the
- * queue, inclusive.
- */
- TimerTask get(int i) {
- return queue[i];
- }
- /**
- * Remove the head task from the priority queue.
- */
- void removeMin() {
- queue[1] = queue[size];
- queue[size--] = null; // Drop extra reference to prevent memory leak
- fixDown(1);//调整堆结构----->所谓的下滤
- }
- /**
- * Removes the ith element from queue without regard for maintaining
- * the heap invariant. Recall that queue is one-based, so
- * 1 <= i <= size.
- */
- void quickRemove(int i) {
- assert i <= size;
- queue[i] = queue[size];
- queue[size--] = null; // Drop extra ref to prevent memory leak
- }
- /**
- * Sets the nextExecutionTime associated with the head task to the
- * specified value, and adjusts priority queue accordingly.
- */
- void rescheduleMin(long newTime) {
- queue[1].nextExecutionTime = newTime;
- fixDown(1);
- }
- /**
- * Returns true if the priority queue contains no elements.
- */
- boolean isEmpty() {
- return size==0;
- }
- /**
- * Removes all elements from the priority queue.
- */
- void clear() {
- // Null out task references to prevent memory leak
- for (int i=1; i<=size; i++)
- queue[i] = null;
- size = 0;
- }
- /**
- * Establishes the heap invariant (described above) assuming the heap
- * satisfies the invariant except possibly for the leaf-node indexed by k
- * (which may have a nextExecutionTime less than its parent's).
- *
- * This method functions by "promoting" queue[k] up the hierarchy
- * (by swapping it with its parent) repeatedly until queue[k]'s
- * nextExecutionTime is greater than or equal to that of its parent.
- */
- private void fixUp(int k) {
- while (k > 1) {
- int j = k >> 1;
- if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
- break;
- TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
- k = j;
- }
- }
- /**
- * Establishes the heap invariant (described above) in the subtree
- * rooted at k, which is assumed to satisfy the heap invariant except
- * possibly for node k itself (which may have a nextExecutionTime greater
- * than its children's).
- *
- * This method functions by "demoting" queue[k] down the hierarchy
- * (by swapping it with its smaller child) repeatedly until queue[k]'s
- * nextExecutionTime is less than or equal to those of its children.
- */
- private void fixDown(int k) {
- int j;
- while ((j = k << 1) <= size && j > 0) {
- if (j < size &&
- queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
- j++; // j indexes smallest kid
- if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
- break;
- TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
- k = j;
- }
- }
- /**
- * Establishes the heap invariant (described above) in the entire tree,
- * assuming nothing about the order of the elements prior to the call.
- */
- void heapify() {//建堆操作,从第一个非叶子结点開始。
- for (int i = size/2; i >= 1; i--)
- fixDown(i);
- }
- }
- class TimerThread extends Thread {
- /**
- * This flag is set to false by the reaper to inform us that there
- * are no more live references to our Timer object. Once this flag
- * is true and there are no more tasks in our queue, there is no
- * work left for us to do, so we terminate gracefully. Note that
- * this field is protected by queue's monitor!
- */
- boolean newTasksMayBeScheduled = true;
- /**
- * Our Timer's queue. We store this reference in preference to
- * a reference to the Timer so the reference graph remains acyclic.
- * Otherwise, the Timer would never be garbage-collected and this
- * thread would never go away.
- */
- private TaskQueue queue;//持有任务队列的引用
- TimerThread(TaskQueue queue) {
- this.queue = queue;
- }
- 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
- 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) {
- }
- }
- }
- }
凝视写的非常明确。TimerThread会在run方法中调用mainloop方法。这是一个死循环,不断从任务队列中取出任务。运行之,假设没有任务可运行,将会wait,等待队列非空,而Timer类的schedule方法会调用notify唤醒该线程。运行任务。
- private void sched(TimerTask task, long time, long period) {//全部的schedule方法都会调用此方法
- 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();//唤醒任务运行线程
- }
- }
那么TimerThread何时被启动的呢?猜猜也能知道,肯定是Timer被创建时运行的:
- public Timer(String name) {
- thread.setName(name);
- thread.start();//启动线程
- }
当我们主线程运行完成后。Timer线程可能仍然处于堵塞或者其它状态,有时这不是我们希望看到的,Timer类有这样一个构造器,能够让任务运行线程以守护线程的方式运行。这样当主线程运行完成后。守护线程也会停止。
- public Timer(boolean isDaemon) {
- this("Timer-" + serialNumber(), isDaemon);
- }
以上就是Timer类的源代码分析过程。最后贴上一张图。帮助理解:
【源代码】Timer和TimerTask源代码剖析的更多相关文章
- Java并发编程:Timer和TimerTask(转载)
Java并发编程:Timer和TimerTask(转载) 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer ...
- Java线程:Timer和TimerTask
Timer和TimerTask可以做为实现线程的第三种方式,前两中方式分别是继承自Thread类和实现Runnable接口. Timer是一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务执 ...
- Java中的Timer和TimerTask在Android中的用法(转)
转自:http://blog.csdn.net/zuolongsnail/article/details/8168689 在开发中我们有时会有这样的需求,即在固定的每隔一段时间执行某一个任务.比如UI ...
- Java定时任务Timer、TimerTask与ScheduledThreadPoolExecutor详解
定时任务就是在指定时间执行程序,或周期性执行计划任务.Java中实现定时任务的方法有很多,本文从从JDK自带的一些方法来实现定时任务的需求. 一.Timer和TimerTask Timer和Tim ...
- JDK中的Timer和TimerTask详解(zhuan)
http://www.cnblogs.com/lingiu/p/3782813.html ************************************************** 目录结构 ...
- Timer与TimerTask的真正原理&使用介绍
转载: Timer与TimerTask的真正原理&使用介绍 其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类,而具体的TimerTask需要由你自己来 ...
- Java并发编程:Timer和TimerTask
Java并发编程:Timer和TimerTask 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer来讲就是 ...
- android Timer and TImerTask
android Timer and TImerTask Caused by: java.lang.IllegalStateException: TimerTask is scheduled alrea ...
- java中计时器的用法Timer和TimerTask的用法__java中利用Timer与TImerTask 计时器间隔执行任务
经常我们都会有这样的需求,要固定的每隔一段时间执行某一个任务.比如: 我们做一个缓存来减少与数据库的交互,而为了使缓存与数据库中的数据尽量达到同步,需要每个固定的一段时间去数据库中的数 ...
随机推荐
- 【LeetCode-面试算法经典-Java实现】【130-Surrounded Regions(围绕区域)】
[130-Surrounded Regions(围绕区域)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a 2D board containing 'X ...
- Windows/Linux下磁盘使用的图形化工具简介
Windows/Linux下磁盘使用的图形化工具简介 如何以图形界面查看磁盘及分区的大小及剩余容量呢?今天我为大家介绍两款Windows/Linux下磁盘使用的图形化工具分别是Spacesniff ...
- Codefroces 760 B. Frodo and pillows
B. Frodo and pillows time limit per test 1 second memory limit per test 256 megabytes input standard ...
- Android Studio com.android.dex.DexException: Multiple dex files define(重复引用包)
如果你用Android Studio开发,并且要用其他项目作为library,这个问题是很容易出现的.出现这个问题的原因是包的重复引用,意思就是在你自己的项目中引用了某个包,而被你作为library的 ...
- 【hdu 6000】Wash
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 因为每件衣服都是没有区别的. 只有洗衣机不同会影响洗衣时间. 那么我们把每台洗衣机洗衣的时间一开始都加入到队列中. 比如{2,3,6 ...
- 关于PyYAML报错问题解决
转自:http://www.fwqtg.net/%E5%85%B3%E4%BA%8Epyyaml%E6%8A%A5%E9%94%99%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86% ...
- (最新)使用爬虫刷CSDN博客访问量——亲测有效
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 1.概述 前言:前两天刚写了第一篇博客https://blog.csdn.net/qq_41782425/article/deta ...
- GPUImage ==> 一个基于GPU图像和视频处理的开源iOS框架
Logo 项目介绍: GPUImage是Brad Larson在github托管的开源项目. GPUImage是一个基于GPU图像和视频处理的开源iOS框架,提供各种各样的图像处理滤镜,并且支持照相机 ...
- GO语言学习(四)GO语言语言结构
Go Hello World 实例 Go 语言的基础组成有以下几个部分: 包声明 引入包 函数 变量 语句 & 表达式 注释 接下来让我们来看下简单的代码,该代码输出了"Hello ...
- asp.net获取客户真实ip非代理ip:
public string GetUserIP() { string _userIP; if(Request.ServerVariables["HTTP_VIA& ...