先来看下timer的调用方式,简单的定时打印java
public static void main(String[] args){ Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }, 5000, 5000); }
运行结果:node
Timer-0
Timer-0
Timer-0
Timer-0
Timer-0多线程
而后我好奇它是如何实现定时调用的,打开TimerTask类的源码,发现它是一个对runable的封装,添加了一些状态和同步锁对象以及下次执行的时间,它封装了如下状态ide
/**
* This task has not yet been scheduled.任务尚未被调用
*/
static final int VIRGIN = 0;oop
/**
* This task is scheduled for execution. If it is a non-repeating task,
* it has not yet been executed. 任务被调度去执行,若是是一个不循环执行的任务,表示它尚未被执行
*/
static final int SCHEDULED = 1;ui
/**
* This non-repeating task has already executed (or is currently
* executing) and has not been cancelled.不重复执行任务已经执行或者正在执行,不能被取消
*/
static final int EXECUTED = 2;this
/**
* This task has been cancelled (with a call to TimerTask.cancel).任务已经被取消,(调用 timerTask 的cancel 方法
*/
static final int CANCELLED = 3;线程
/**code
* 下次执行的时间,System.currentTimeMillis 格式
* Next execution time for this task in the format returned by
* System.currentTimeMillis, assuming this task is scheduled for execution.
* For repeating tasks, this field is updated prior to each task execution.
*/
long nextExecutionTime;orm
/**
* 执行间隔
* Period in milliseconds for repeating tasks. A positive value indicates
* fixed-rate execution. A negative value indicates fixed-delay execution.
* A value of 0 indicates a non-repeating task.
*/
long period = 0;
以上能够看出timer+timerTask的方式不适合使用天然时间的任务。
Timer.class
timer主要有两个关键的成员变量final修饰
//内部类实现,timerTask的队列,封装实现了,最大128个任务
private final TaskQueue queue = new TaskQueue();
/**
* The timer thread.,内部类,一个线程的封装实现
*/
private final TimerThread thread = new TimerThread(queue);
先简单介绍下TaskQueue.class,当作员变量
/**
保存定时任务队列,能够看到最大一个timer最多能够提交128个任务
* 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];
/**
* The number of tasks in the priority queue. (The tasks are stored in
* queue[1] up to queue[size]).
*/
private int size = 0;
TaskQueue提供了一系列方法是对该队列即将执行的任务的操做,获取最近要执行的人,修改任务的下次执行时间
主要是有两个私有方法fixUp(),fixDown();用来更新队列的顺序。
再来看下TimerThread.class,主要看下run方法
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)实现线程一直在运行,而不是任务到时间了另起一个线程,因此timer只有一个线程 while (true) { try { TimerTask task; boolean taskFired; synchronized(queue) { // Wait for queue to become non-empty while (queue.isEmpty() && newTasksMayBeScheduled) //new timer()的时候线程已经启动了的,在这里等带任务的提交,为何是用while呢? queue.wait(); if (queue.isEmpty())//队列空直接退出,在中止timer的状况下 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) { } } } }
能够看到timer的定时实际上是使用一个线程while(true)和,wait(),notify()配合实现的。代码有注释很少解释了。
总结:
jdk timer + timertask的方式实现的定时任务,因为实现方式的局限性,致使不能支持更多的特性,多线程,天然时间等。