/** * The main timer loop. (See class comment.) * 线程处于轮询状态 * - 优先级队列无任务 * - 无限阻塞等待有任务添加进来显式唤醒线程 * - 优先级队列有任务 * - 任务已经被标识取消 从任务队列中移除 * - 任务执行时机已经过了 继续下一轮的轮询 * - 任务可以执行 * - 只需要调度一次 从任务队列移除 * - 周而复始的定时任务 更新下一次调度时间 */ privatevoidmainLoop() { while (true) { try { TimerTask task; boolean taskFired; synchronized(queue) { // 保证了任务的有序性 // Wait for queue to become non-empty while (queue.isEmpty() && newTasksMayBeScheduled) queue.wait(); // 等有任务进来 不然就把线程无限阻塞只到外界有任务添加进来 显式notify这个阻塞线程 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) { } } }
2.3 TaskQueue
优先级队列的实现,小根堆,数据结构使用的是数组,那么规则如下:
为了使用数组构造二叉树结构,假设root脚标为x,则:
left节点脚标为2x
right节点脚标为2x+1
这样的规则就要弃用数组中脚标0,实际存储元素重下标[1…]开始。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/** * The number of tasks in the priority queue. (The tasks are stored in * queue[1] up to queue[size]). * * 数组中元素数量 * 为了构造二叉树结构 * 假设root脚标为x 则 * - left节点脚标为2x * - right节点脚标为2x+1 * 这样的规则就要避开脚标0 意味着数组中脚标0弃用 * 实际存储元素从下标[1...]开始 * 那么当队列中有size个元素时 数据下标已经用到了size */ privateintsize=0;