就以闹钟的例子开头吧(后续小节皆以闹钟为例,全部源代码只列关键部分)。java
public class ScheduleDemo { public static void main(String[] args) throws InterruptedException { long delay = 1000; // 一秒后开始执行 long period = 2000; // 执行间隔 Timer timer = new Timer(); AlarmTask alarm = new AlarmTask("闹钟1"); log.info("["+Thread.currentThread().getName()+"]开启闹钟调度!"); timer.schedule(alarm,delay,period); } /** * 模拟闹钟 */ static class AlarmTask extends TimerTask{ String name ; public AlarmTask(String name){ this.name=name; } @Override public void run() { log.info("["+Thread.currentThread().getName()+"]"+name+":嘀。。。"); Thread.sleep(1000); //模拟闹钟执行时间,省略异常。。。 } } }
一秒之后闹钟每隔两秒执行一次。ide
[main] 开启闹钟调度! [Timer-0] 闹钟1:嘀。。。 [Timer-0] 闹钟1:嘀。。。 [Timer-0] 闹钟1:嘀。。。
从打印结果能够看到,闹钟调度与执行并不是一线程。oop
下面是Timer时序图,能够了解Timer的大概流程。源码分析
下面开始分析Timer源码。this
public class Timer { private final TaskQueue queue = new TaskQueue(); private final TimerThread thread = new TimerThread(queue); public Timer() { this("Timer-" + serialNumber()); } public Timer(String name) { thread.setName(name); thread.start(); }
能够看到,Timer中维护了一个内部线程与队列,且在实例化Timer的同时,就已初始化好了。在初始化Timer时,内部线程TimerThread开始启动,下面是TimerThread的执行过程。spa
class TimerThread extends Thread { public void run() { mainLoop(); } private void mainLoop() { while (true) { synchronized(queue) { // 队列为空,线程被阻塞 while (queue.isEmpty() && newTasksMayBeScheduled) queue.wait();
能够看到,虽然线程TimerThread已启动,但因队列为空,线程被阻塞(等待queue锁)。线程
以上是Timer timer = new Timer()的整个运行过程,继续看timer.schedule(alarm,delay,period)。code
public class Timer { public void schedule(TimerTask task, long delay, long period) { sched(task, System.currentTimeMillis()+delay, -period); } private void sched(TimerTask task, long time, long period) { synchronized(queue) { synchronized(task.lock) { task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; } // 将闹钟加入队列 queue.add(task); // 此时正好知足条件,主线程释放queue锁,并唤醒TimerThread if (queue.getMin() == task) queue.notify(); } }
从源码可看出,主线程正好知足queue.getMin() == task,此时将唤醒TimerThread线程(waiting)并释放queue锁。队列
下面再切换到TimerThread的运行场景。get
private void mainLoop() { while (true) { synchronized(queue) { while (queue.isEmpty() && newTasksMayBeScheduled) queue.wait(); if (queue.isEmpty()) break; task = queue.getMin(); synchronized(task.lock) { currentTime = System.currentTimeMillis(); executionTime = task.nextExecutionTime; // 已经到了执行时间 if (taskFired = (executionTime<=currentTime)) { // ...从新定义下次闹钟执行时间 } } if (!taskFired) // 执行时间未到,线程再次阻塞 queue.wait(executionTime - currentTime); } if (taskFired) task.run(); // 同步执行用户定义的闹钟 } }
经过上面的源码分析,TimerThread被唤醒后,将判断执行时间,时间到则初始化下次闹钟的执行时间并运行本次闹钟,不然线程将等待指定时间。
如此周而复始。。