`

深入JDK源代码之定时操作Timer类和TimerTask类实现

    博客分类:
  • java
阅读更多
    Timer类是一种线程设施,可以用来实现某一个时间或某一段时间后安排某一个任务执行一次或定期重复执行。该功能和TimerTask配合使用。TimerTask类用于实现由Timer安排的一次或重复执行的某个任务。每一个Timer对象对应的是一个线程,因此计时器所执行的任务应该迅速完成,否则会延迟后续的任务执行。
  一、 深入JDK源代码TimerTask类,发现这个类是个抽象类比较简单,有四个常量表示定时器任务的状态,还有一个Object类型lock对象,相当一把锁,控制线程对定时器任务状态的同步访问。
  nextExecutionTime 这个成员变量用到记录该任务下次执行时间, 其格式和System.currentTimeMillis()一致.
这个值是作为任务队列中任务排序的依据. 任务调试者执行每个任务前会对这个值作处理,重新计算下一次任务执行时间,并为这个变量赋值.
  period 用来描述任务的执行方式: 0表示不重复执行的任务. 正数表示固定速率执行的任务. 负数表示固定延迟执行的任务.
(固定速率: 不考虑该任务上一次执行情况,始终从开始时间算起的每period执行下一次.   固定延迟: 考虑该任务一次执行情况,在上一次执行后period执行下一次).
代码如下:
public abstract class TimerTask implements Runnable {
	//这个对象是用来控制访问TimerTask内部构件。锁机制
    final Object lock = new Object();
    //定时器任务的状态
    int state = VIRGIN;
    //定时器任务默认的状态,表示还没有被安排
    static final int VIRGIN = 0;
    //表示定时器任务被安排了
    static final int SCHEDULED   = 1;
    //表示定时器任务执行
    static final int EXECUTED    = 2;
    //表示定时器任务取消
    static final int CANCELLED   = 3;
    //下次执行任务时间
    long nextExecutionTime;
    long period = 0;

    protected TimerTask() {
    }
   // 此计时器任务要执行的操作。
    public abstract void run();

    // 取消此计时器任务。
    public boolean cancel() {
        synchronized(lock) {
            boolean result = (state == SCHEDULED);
            state = CANCELLED;
            return result;
        }
    }
    // 返回此任务最近实际 执行的已安排 执行时间。
    public long scheduledExecutionTime() {
        synchronized(lock) {
            return (period < 0 ? nextExecutionTime + period
                               : nextExecutionTime - period);
        }
    }
}

二、深入JDK源代码之Timer类,Timer中最主要由三个部分组成: 任务 TimerTask 、  任务队列: TaskQueue queue任务调试者:TimerThread thread
1.任务队列 TaskQueue,它是Timer的一个内部类。
    事实上任务队列是一个数组, 采用平衡二叉堆来实现他的优先级调度, 并且是一个小顶堆. 需要注意的是, 这个堆中queue[n] 的孩子是queue[2*n] 和 queue[2*n+1].
    任务队列的优先级按照TimerTask类的成员变量nextExecutionTime值来排序(注意, 这里的任务指的是那些交由定时器来执行的, 继承TimerTask的对象).
    在任务队列中, nextExecutionTime最小就是所有任务中最早要被调度来执行的, 所以被安排在queue[1] (假设任务队列非空).
    对于堆中任意一个节点n, 和他的任意子孙节点d,一定遵循: n.nextExecutionTime <= d.nextExecutionTime.
// 任务队列
class TaskQueue {
	// 计时器任务数组,默认大小为128
	private TimerTask[] queue = new TimerTask[128];

	private int size = 0;

	int size() {
		return size;
	}

	// 加入队列
	void add(TimerTask task) {
		// Grow backing store if necessary
		if (size + 1 == queue.length)
			// 队列以两倍的速度扩容
			queue = Arrays.copyOf(queue, 2 * queue.length);

		queue[++size] = task;
		fixUp(size);
	}

	// 获取队列的地二个元素,即第一个任务,第一个元素存储的是
	TimerTask getMin() {
		return queue[1];
	}

	TimerTask get(int i) {
		return queue[i];
	}

	// 消除头任务从优先队列。
	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;
	}

	// 进行队列中任务优先级调整. fixUp方法的作用是尽量将队列中指定位置(k)的任务向队列前面移动,
	// 即提高它的优先级. 因为新加入的方法很有可能比已经在任务队列中的其它任务要更早执行.
	private void fixUp(int k) {
		while (k > 1) {
			int j = k >> 1;// 左移一位,相当于除以2
			if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
				break;
			TimerTask tmp = queue[j];
			queue[j] = queue[k];
			queue[k] = tmp;
			k = j;
		}
	}

	// 从任务队列中移除一个任务的过程, 首先直接将当前任务队列中最后一个任务赋给queue[1],
	// 然后将队列中任务数量--, 最后和上面类似, 但是这里是调用fixDown(int k)方法了, 尽量将k位置的任务向队列后面移动.
	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);
	}
}
    

2.任务调度 TimerThread
// 计时器线程
class TimerThread extends Thread {

	// 新任务是否被安排
	boolean newTasksMayBeScheduled = true;

	// 任务队列
	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
			}
		}
	}

	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) {
			}
		}
	}
}

3.Timer类的主体和主要对外提供的方法
import java.util.*;
import java.util.Date;

public class Timer {
	// 定时任务队列
	private TaskQueue queue = new TaskQueue();

	// 计时器线程
	private TimerThread thread = new TimerThread(queue);

	private Object threadReaper = new Object() {
		protected void finalize() throws Throwable {
			synchronized (queue) {
				thread.newTasksMayBeScheduled = false;
				queue.notify(); // In case queue is empty.
			}
		}
	};

	// ID号作为线程的ID
	private static int nextSerialNumber = 0;

	private static synchronized int serialNumber() {
		return nextSerialNumber++;
	}

	public Timer() {
		this("Timer-" + serialNumber());
	}

	// 创建一个新计时器,可以指定其相关的线程作为守护程序运行。
	public Timer(boolean isDaemon) {
		this("Timer-" + serialNumber(), isDaemon);
	}

	public Timer(String name) {
		thread.setName(name);
		thread.start();
	}

	// 创建一个新计时器,其相关的线程具有指定的名称,并且可以指定作为守护程序运行。
	public Timer(String name, boolean isDaemon) {
		thread.setName(name);
		thread.setDaemon(isDaemon);
		thread.start();
	}

	// 安排在指定延迟后执行指定的任务。时间单位毫秒
	public void schedule(TimerTask task, long delay) {
		if (delay < 0)
			throw new IllegalArgumentException("Negative delay.");
		sched(task, System.currentTimeMillis() + delay, 0);
	}

	// 安排在指定的时间执行指定的任务。
	public void schedule(TimerTask task, Date time) {
		sched(task, time.getTime(), 0);
	}

	// 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
	public void schedule(TimerTask task, long delay, long period) {
		if (delay < 0)
			throw new IllegalArgumentException("Negative delay.");
		if (period <= 0)
			throw new IllegalArgumentException("Non-positive period.");
		sched(task, System.currentTimeMillis() + delay, -period);
	}

	// 安排指定的任务在指定的时间开始进行重复的固定延迟执行。
	public void schedule(TimerTask task, Date firstTime, long period) {
		if (period <= 0)
			throw new IllegalArgumentException("Non-positive period.");
		sched(task, firstTime.getTime(), -period);
	}

	// 安排指定的任务在指定的延迟后开始进行重复的固定速率执行。
	public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
		if (delay < 0)
			throw new IllegalArgumentException("Negative delay.");
		if (period <= 0)
			throw new IllegalArgumentException("Non-positive period.");
		sched(task, System.currentTimeMillis() + delay, period);
	}

	// 安排指定的任务在指定的时间开始进行重复的固定速率执行。
	public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
		if (period <= 0)
			throw new IllegalArgumentException("Non-positive period.");
		sched(task, firstTime.getTime(), period);
	}
	private void sched(TimerTask task, long time, long period) {
		if (time < 0)
			throw new IllegalArgumentException("Illegal execution time.");
		// 同步代码块 ,对queue的访问需要同步
		synchronized (queue) {
			if (!thread.newTasksMayBeScheduled)
				throw new IllegalStateException("Timer already cancelled.");
			// 同步代码块,需要获得task的lock,锁
			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();
		}
	}

	// 终止此计时器,丢弃所有当前已安排的任务。
	public void cancel() {
		synchronized (queue) {
			thread.newTasksMayBeScheduled = false;
			queue.clear();
			queue.notify(); // In case queue was already empty.
		}
	}

	// 从此计时器的任务队列中移除所有已取消的任务。
	public int purge() {
		int result = 0;

		synchronized (queue) {
			for (int i = queue.size(); i > 0; i--) {
				if (queue.get(i).state == TimerTask.CANCELLED) {
					queue.quickRemove(i);
					result++;
				}
			}

			if (result != 0)
				queue.heapify();
		}

		return result;
	}
}

参考:http://japi.iteye.com/blog/1022656
0
3
分享到:
评论

相关推荐

    Timer和TimerTask的使用

    `Timer` 和 `TimerTask` 是Java中用于实现定时任务的重要工具。它们提供了一种简单有效的方式来安排任务的执行,既可以一次性执行也可以周期性地执行。这对于实现定时提醒、定时备份等功能非常有用。 #### 二、...

    java jdk源代码

    Java JDK源代码是Java开发工具包的原始代码,对于任何想要深入理解Java语言工作原理的开发者来说,它都是一个无价的学习资源。JDK包含了Java运行环境、编译器、类库以及各种工具,它的源代码揭示了Java平台的内部...

    JDK源代码Java源码

    总的来说,深入研究JDK1.8的源代码不仅可以帮助我们提高编程技能,理解语言特性的实现,还可以培养出解决问题和调试的高级技巧。通过分析源码,我们能够发现潜在的性能瓶颈,优化代码,甚至为开源社区贡献自己的力量...

    spring + jdk TimerTask定时器

    本文将深入探讨如何在Spring框架中结合JDK的`TimerTask`来创建和管理定时任务。 ### Spring定时任务简介 Spring提供了`org.springframework.scheduling`包,其中包含用于调度任务的组件。最常用的有两种方式:基于...

    Jdk的Timer 实现定时器

    在提供的压缩包文件`ch08_timer`中,可能包含了一些示例代码,展示了如何使用`Timer`和`TimerTask`来实现进度条的更新或其他定时任务。通过学习和理解这些代码,开发者可以更好地掌握`Timer`类的用法,并将其应用到...

    jdk 1.6 源代码一

    6. **JVM接口**:虽然JDK源代码不包含JVM本身,但`sun.misc`和`sun.reflect`包提供了一些与JVM交互的接口,如`Unsafe`类,它允许我们执行一些底层操作。 7. **国际化与本地化**:`java.text`和`java.util.locale`包...

    JDK1.8源代码

    下面我们将深入探讨JDK 1.8源代码中的关键知识点。 1. **Lambda表达式**: JDK 1.8中最重要的更新之一就是引入了Lambda表达式,这是一种简洁的匿名函数表示方式,使得编写函数式编程风格的Java代码变得更加容易。...

    java类Timer和TimerTask的使用.pdf

    Java中的`Timer`和`TimerTask`类是用于创建和管理定时任务的工具,它们提供了在特定时间点或按照预设间隔执行任务的功能。这两个类是Java标准库`java.util`包的一部分,对于需要定时执行操作的应用场景非常有用。 `...

    jdk源代码src.zip

    本文将围绕"jdk8源代码src.zip"展开,带你走进JDK8源代码的深处,探索其内在的编程思想和实现细节。 首先,"src.zip"文件包含了JDK8的源代码,它是开发者研究Java核心类库的重要资源。通过解压这个zip文件,我们...

    java jdk 宝典 源代码

    Java JDK宝典源代码是Java开发者的宝贵资源,它提供了Java开发工具包(JDK)的核心类库和实现的原始源代码。对于深入理解Java语言、API的工作原理以及进行问题排查,阅读源代码是非常有益的。这篇博文中,博主分享了...

    jdk1.5.0_12源代码

    在JDK1.5.0_12的源代码中,可以看到编译器如何处理这种转换,例如,当基本类型与包装类进行操作时,编译器会自动添加装箱和拆箱的操作。 4. **变长参数(Varargs)**: 变长参数允许一个方法接受不定数量的参数。...

    JDK7源代码

    《深入解析JDK7源代码》 JDK7(Java Development Kit 7)是Java编程语言的一个重要版本,它的源代码对于理解Java平台的工作原理、学习面向对象编程以及提升编程技巧具有极大的价值。在这个资源中,包含了 javax、...

    jdk1.4.2源代码

    通过源代码,开发者可以学习到如何设计高效的代码和数据结构,以及如何利用JVM特性提高程序性能。 四、安全机制 JDK1.4.2的安全模型是Java平台的一个重要特性,包括类加载器的隔离、安全管理器、访问控制等。源...

    JAVA JDK完整源代码

    Java JDK完整源代码是开发者深入理解Java平台工作原理和实现机制的重要资源。它包含了Java开发工具集(Java Development Kit)的所有核心组件的源代码,帮助程序员在遇到问题时能够查看底层实现,提升学习和调试效率...

    jdk-1.6.0 源代码 二

    尽管只提供了JDK 1.6.0源代码的一部分,但这部分仍然包含了大量关键组件和机制的实现。通过深入研究,开发者不仅可以提高对Java平台的理解,也能学习到很多设计模式和最佳实践,对提升编程技能大有裨益。

    JDK各种类、方法源代码

    在Java开发中,深入理解JDK的源代码是提升编程技能的重要步骤。JDK,全称为Java Development Kit,是Oracle公司提供的Java编程语言的标准开发工具集。它包含了编译器、运行时环境以及一系列用于创建和运行Java应用...

    jdk1.1源代码

    通过研究JDK1.1的源代码,开发者可以追溯到Java语言的起源,了解其设计理念和发展脉络,同时也能对比现代Java的改进,从而更好地理解和应用现代编程实践。尽管许多特性已经过时,但它们为后续版本的Java奠定了坚实的...

    JDK宝典源代码.rar

    《JDK宝典源代码》是一份珍贵的学习资源,它包含了Java开发工具包(JDK)的源代码,是深入理解Java语言底层实现的关键。在开源的推动下,越来越多的技术爱好者能够接触到这样的核心资料,从而提升自己的编程技能。这...

    JAVA JDK1.6源代码

    对于Java开发者来说,深入理解JDK源代码能够提升编程技能,了解底层实现,优化代码性能,以及解决复杂问题。以下将从多个方面详细介绍JDK1.6源代码中的关键知识点。 1. **核心类库解析** - `java`包:包含Java标准...

Global site tag (gtag.js) - Google Analytics