Timer Class Introduction 在JDK库中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某任务。
A Simple Example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class TimerTest { private static Timer timer = new Timer(); static public class MyTask extends TimerTask { private String str; public MyTask (String str) { this .str = str; } @Override public void run () { System.out.println(this .str + "running:" + new Date()); } } public static void main (String[] args) throws ParseException { MyTask myTask1 = new MyTask("task1" ); MyTask myTask2 = new MyTask("task2" ); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss" ); String dateString1 = "2017-07-26 10:06:01" ; Date date1 = sdf.parse(dateString1); String dateString2 = "2017-07-26 10:05:01" ; Date date2 = sdf.parse(dateString2); timer.schedule(myTask1, date1); timer.schedule(myTask2, date2); } }
在这个例子中,定义了两个TimerTask,并且设定执行时间,调用Timer的schedule()方法,传入任务和时间,执行正确。
Timer源码分析 首先我们以timer.schedule()方法为入口,进一步剖析整个执行流程。看看Timer的schedule()的源码:
1 2 3 public void schedule (TimerTask task, Date time) { sched(task, time.getTime(), 0 ); }
再进一步看sched()方法的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private void sched (TimerTask task, long time, long period) { if (time < 0 ) throw new IllegalArgumentException("Illegal execution time." ); 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的基本属性,包括nextExecutionTime、perid、state; 将task添加到queue中,等待task被执行; TaskQueue源码分析 底层是定义了一个private TimerTask[] queue = new TimerTask[128]; 数组,用来存储TimerTask,默认值为128; TaskQueue是直接定义在Timer.java的类,是一个优先级队列,是根据nextExecutionTime排序的;最小的nextExecutionTime 如果queue不是空的,最小的TimeTask.nextExecutionTime就是queue[1]; 主要理解两个函数:fixUp()和fixDown(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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; } } 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++; if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime) break ; TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; k = j; } }
每次调用add()方法,先将任务添加到quene的最后一个,然后调用fixUp()方法,调整整个queue,将拥有最小nextExecutionTime的TimerTask调整到queue[1]位置,如果位置不够,则需要扩容,按照原来容量的两倍扩容;