0N/A/*
2362N/A * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.util;
0N/Aimport java.util.Date;
471N/Aimport java.util.concurrent.atomic.AtomicInteger;
0N/A
0N/A/**
0N/A * A facility for threads to schedule tasks for future execution in a
0N/A * background thread. Tasks may be scheduled for one-time execution, or for
0N/A * repeated execution at regular intervals.
0N/A *
0N/A * <p>Corresponding to each <tt>Timer</tt> object is a single background
0N/A * thread that is used to execute all of the timer's tasks, sequentially.
0N/A * Timer tasks should complete quickly. If a timer task takes excessive time
0N/A * to complete, it "hogs" the timer's task execution thread. This can, in
0N/A * turn, delay the execution of subsequent tasks, which may "bunch up" and
0N/A * execute in rapid succession when (and if) the offending task finally
0N/A * completes.
0N/A *
0N/A * <p>After the last live reference to a <tt>Timer</tt> object goes away
0N/A * <i>and</i> all outstanding tasks have completed execution, the timer's task
0N/A * execution thread terminates gracefully (and becomes subject to garbage
0N/A * collection). However, this can take arbitrarily long to occur. By
0N/A * default, the task execution thread does not run as a <i>daemon thread</i>,
0N/A * so it is capable of keeping an application from terminating. If a caller
0N/A * wants to terminate a timer's task execution thread rapidly, the caller
0N/A * should invoke the timer's <tt>cancel</tt> method.
0N/A *
0N/A * <p>If the timer's task execution thread terminates unexpectedly, for
0N/A * example, because its <tt>stop</tt> method is invoked, any further
0N/A * attempt to schedule a task on the timer will result in an
0N/A * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
0N/A * method had been invoked.
0N/A *
0N/A * <p>This class is thread-safe: multiple threads can share a single
0N/A * <tt>Timer</tt> object without the need for external synchronization.
0N/A *
0N/A * <p>This class does <i>not</i> offer real-time guarantees: it schedules
0N/A * tasks using the <tt>Object.wait(long)</tt> method.
0N/A *
0N/A * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
0N/A * one of the concurrency utilities therein is the {@link
0N/A * java.util.concurrent.ScheduledThreadPoolExecutor
0N/A * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
0N/A * executing tasks at a given rate or delay. It is effectively a more
0N/A * versatile replacement for the {@code Timer}/{@code TimerTask}
0N/A * combination, as it allows multiple service threads, accepts various
0N/A * time units, and doesn't require subclassing {@code TimerTask} (just
0N/A * implement {@code Runnable}). Configuring {@code
0N/A * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
0N/A * {@code Timer}.
0N/A *
0N/A * <p>Implementation note: This class scales to large numbers of concurrently
0N/A * scheduled tasks (thousands should present no problem). Internally,
0N/A * it uses a binary heap to represent its task queue, so the cost to schedule
0N/A * a task is O(log n), where n is the number of concurrently scheduled tasks.
0N/A *
0N/A * <p>Implementation note: All constructors start a timer thread.
0N/A *
0N/A * @author Josh Bloch
0N/A * @see TimerTask
0N/A * @see Object#wait(long)
0N/A * @since 1.3
0N/A */
0N/A
0N/Apublic class Timer {
0N/A /**
0N/A * The timer task queue. This data structure is shared with the timer
0N/A * thread. The timer produces tasks, via its various schedule calls,
0N/A * and the timer thread consumes, executing timer tasks as appropriate,
0N/A * and removing them from the queue when they're obsolete.
0N/A */
479N/A private final TaskQueue queue = new TaskQueue();
0N/A
0N/A /**
0N/A * The timer thread.
0N/A */
479N/A private final TimerThread thread = new TimerThread(queue);
0N/A
0N/A /**
0N/A * This object causes the timer's task execution thread to exit
0N/A * gracefully when there are no live references to the Timer object and no
0N/A * tasks in the timer queue. It is used in preference to a finalizer on
0N/A * Timer as such a finalizer would be susceptible to a subclass's
0N/A * finalizer forgetting to call it.
0N/A */
479N/A private final Object threadReaper = new Object() {
0N/A protected void finalize() throws Throwable {
0N/A synchronized(queue) {
0N/A thread.newTasksMayBeScheduled = false;
0N/A queue.notify(); // In case queue is empty.
0N/A }
0N/A }
0N/A };
0N/A
0N/A /**
471N/A * This ID is used to generate thread names.
0N/A */
479N/A private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
471N/A private static int serialNumber() {
471N/A return nextSerialNumber.getAndIncrement();
0N/A }
0N/A
0N/A /**
0N/A * Creates a new timer. The associated thread does <i>not</i>
0N/A * {@linkplain Thread#setDaemon run as a daemon}.
0N/A */
0N/A public Timer() {
0N/A this("Timer-" + serialNumber());
0N/A }
0N/A
0N/A /**
0N/A * Creates a new timer whose associated thread may be specified to
0N/A * {@linkplain Thread#setDaemon run as a daemon}.
0N/A * A daemon thread is called for if the timer will be used to
0N/A * schedule repeating "maintenance activities", which must be
0N/A * performed as long as the application is running, but should not
0N/A * prolong the lifetime of the application.
0N/A *
0N/A * @param isDaemon true if the associated thread should run as a daemon.
0N/A */
0N/A public Timer(boolean isDaemon) {
0N/A this("Timer-" + serialNumber(), isDaemon);
0N/A }
0N/A
0N/A /**
0N/A * Creates a new timer whose associated thread has the specified name.
0N/A * The associated thread does <i>not</i>
0N/A * {@linkplain Thread#setDaemon run as a daemon}.
0N/A *
0N/A * @param name the name of the associated thread
0N/A * @throws NullPointerException if {@code name} is null
0N/A * @since 1.5
0N/A */
0N/A public Timer(String name) {
0N/A thread.setName(name);
0N/A thread.start();
0N/A }
0N/A
0N/A /**
0N/A * Creates a new timer whose associated thread has the specified name,
0N/A * and may be specified to
0N/A * {@linkplain Thread#setDaemon run as a daemon}.
0N/A *
0N/A * @param name the name of the associated thread
0N/A * @param isDaemon true if the associated thread should run as a daemon
0N/A * @throws NullPointerException if {@code name} is null
0N/A * @since 1.5
0N/A */
0N/A public Timer(String name, boolean isDaemon) {
0N/A thread.setName(name);
0N/A thread.setDaemon(isDaemon);
0N/A thread.start();
0N/A }
0N/A
0N/A /**
0N/A * Schedules the specified task for execution after the specified delay.
0N/A *
0N/A * @param task task to be scheduled.
0N/A * @param delay delay in milliseconds before task is to be executed.
0N/A * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
0N/A * <tt>delay + System.currentTimeMillis()</tt> is negative.
0N/A * @throws IllegalStateException if task was already scheduled or
0N/A * cancelled, timer was cancelled, or timer thread terminated.
0N/A * @throws NullPointerException if {@code task} is null
0N/A */
0N/A public void schedule(TimerTask task, long delay) {
0N/A if (delay < 0)
0N/A throw new IllegalArgumentException("Negative delay.");
0N/A sched(task, System.currentTimeMillis()+delay, 0);
0N/A }
0N/A
0N/A /**
0N/A * Schedules the specified task for execution at the specified time. If
0N/A * the time is in the past, the task is scheduled for immediate execution.
0N/A *
0N/A * @param task task to be scheduled.
0N/A * @param time time at which task is to be executed.
0N/A * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
0N/A * @throws IllegalStateException if task was already scheduled or
0N/A * cancelled, timer was cancelled, or timer thread terminated.
0N/A * @throws NullPointerException if {@code task} or {@code time} is null
0N/A */
0N/A public void schedule(TimerTask task, Date time) {
0N/A sched(task, time.getTime(), 0);
0N/A }
0N/A
0N/A /**
0N/A * Schedules the specified task for repeated <i>fixed-delay execution</i>,
0N/A * beginning after the specified delay. Subsequent executions take place
0N/A * at approximately regular intervals separated by the specified period.
0N/A *
0N/A * <p>In fixed-delay execution, each execution is scheduled relative to
0N/A * the actual execution time of the previous execution. If an execution
0N/A * is delayed for any reason (such as garbage collection or other
0N/A * background activity), subsequent executions will be delayed as well.
0N/A * In the long run, the frequency of execution will generally be slightly
0N/A * lower than the reciprocal of the specified period (assuming the system
0N/A * clock underlying <tt>Object.wait(long)</tt> is accurate).
0N/A *
0N/A * <p>Fixed-delay execution is appropriate for recurring activities
0N/A * that require "smoothness." In other words, it is appropriate for
0N/A * activities where it is more important to keep the frequency accurate
0N/A * in the short run than in the long run. This includes most animation
0N/A * tasks, such as blinking a cursor at regular intervals. It also includes
0N/A * tasks wherein regular activity is performed in response to human
0N/A * input, such as automatically repeating a character as long as a key
0N/A * is held down.
0N/A *
0N/A * @param task task to be scheduled.
0N/A * @param delay delay in milliseconds before task is to be executed.
0N/A * @param period time in milliseconds between successive task executions.
0N/A * @throws IllegalArgumentException if {@code delay < 0}, or
0N/A * {@code delay + System.currentTimeMillis() < 0}, or
0N/A * {@code period <= 0}
0N/A * @throws IllegalStateException if task was already scheduled or
0N/A * cancelled, timer was cancelled, or timer thread terminated.
0N/A * @throws NullPointerException if {@code task} is null
0N/A */
0N/A public void schedule(TimerTask task, long delay, long period) {
0N/A if (delay < 0)
0N/A throw new IllegalArgumentException("Negative delay.");
0N/A if (period <= 0)
0N/A throw new IllegalArgumentException("Non-positive period.");
0N/A sched(task, System.currentTimeMillis()+delay, -period);
0N/A }
0N/A
0N/A /**
0N/A * Schedules the specified task for repeated <i>fixed-delay execution</i>,
0N/A * beginning at the specified time. Subsequent executions take place at
0N/A * approximately regular intervals, separated by the specified period.
0N/A *
0N/A * <p>In fixed-delay execution, each execution is scheduled relative to
0N/A * the actual execution time of the previous execution. If an execution
0N/A * is delayed for any reason (such as garbage collection or other
0N/A * background activity), subsequent executions will be delayed as well.
0N/A * In the long run, the frequency of execution will generally be slightly
0N/A * lower than the reciprocal of the specified period (assuming the system
0N/A * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
0N/A * consequence of the above, if the scheduled first time is in the past,
0N/A * it is scheduled for immediate execution.
0N/A *
0N/A * <p>Fixed-delay execution is appropriate for recurring activities
0N/A * that require "smoothness." In other words, it is appropriate for
0N/A * activities where it is more important to keep the frequency accurate
0N/A * in the short run than in the long run. This includes most animation
0N/A * tasks, such as blinking a cursor at regular intervals. It also includes
0N/A * tasks wherein regular activity is performed in response to human
0N/A * input, such as automatically repeating a character as long as a key
0N/A * is held down.
0N/A *
0N/A * @param task task to be scheduled.
0N/A * @param firstTime First time at which task is to be executed.
0N/A * @param period time in milliseconds between successive task executions.
0N/A * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
0N/A * {@code period <= 0}
0N/A * @throws IllegalStateException if task was already scheduled or
0N/A * cancelled, timer was cancelled, or timer thread terminated.
0N/A * @throws NullPointerException if {@code task} or {@code firstTime} is null
0N/A */
0N/A public void schedule(TimerTask task, Date firstTime, long period) {
0N/A if (period <= 0)
0N/A throw new IllegalArgumentException("Non-positive period.");
0N/A sched(task, firstTime.getTime(), -period);
0N/A }
0N/A
0N/A /**
0N/A * Schedules the specified task for repeated <i>fixed-rate execution</i>,
0N/A * beginning after the specified delay. Subsequent executions take place
0N/A * at approximately regular intervals, separated by the specified period.
0N/A *
0N/A * <p>In fixed-rate execution, each execution is scheduled relative to the
0N/A * scheduled execution time of the initial execution. If an execution is
0N/A * delayed for any reason (such as garbage collection or other background
0N/A * activity), two or more executions will occur in rapid succession to
0N/A * "catch up." In the long run, the frequency of execution will be
0N/A * exactly the reciprocal of the specified period (assuming the system
0N/A * clock underlying <tt>Object.wait(long)</tt> is accurate).
0N/A *
0N/A * <p>Fixed-rate execution is appropriate for recurring activities that
0N/A * are sensitive to <i>absolute</i> time, such as ringing a chime every
0N/A * hour on the hour, or running scheduled maintenance every day at a
0N/A * particular time. It is also appropriate for recurring activities
0N/A * where the total time to perform a fixed number of executions is
0N/A * important, such as a countdown timer that ticks once every second for
0N/A * ten seconds. Finally, fixed-rate execution is appropriate for
0N/A * scheduling multiple repeating timer tasks that must remain synchronized
0N/A * with respect to one another.
0N/A *
0N/A * @param task task to be scheduled.
0N/A * @param delay delay in milliseconds before task is to be executed.
0N/A * @param period time in milliseconds between successive task executions.
0N/A * @throws IllegalArgumentException if {@code delay < 0}, or
0N/A * {@code delay + System.currentTimeMillis() < 0}, or
0N/A * {@code period <= 0}
0N/A * @throws IllegalStateException if task was already scheduled or
0N/A * cancelled, timer was cancelled, or timer thread terminated.
0N/A * @throws NullPointerException if {@code task} is null
0N/A */
0N/A public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
0N/A if (delay < 0)
0N/A throw new IllegalArgumentException("Negative delay.");
0N/A if (period <= 0)
0N/A throw new IllegalArgumentException("Non-positive period.");
0N/A sched(task, System.currentTimeMillis()+delay, period);
0N/A }
0N/A
0N/A /**
0N/A * Schedules the specified task for repeated <i>fixed-rate execution</i>,
0N/A * beginning at the specified time. Subsequent executions take place at
0N/A * approximately regular intervals, separated by the specified period.
0N/A *
0N/A * <p>In fixed-rate execution, each execution is scheduled relative to the
0N/A * scheduled execution time of the initial execution. If an execution is
0N/A * delayed for any reason (such as garbage collection or other background
0N/A * activity), two or more executions will occur in rapid succession to
0N/A * "catch up." In the long run, the frequency of execution will be
0N/A * exactly the reciprocal of the specified period (assuming the system
0N/A * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
0N/A * consequence of the above, if the scheduled first time is in the past,
0N/A * then any "missed" executions will be scheduled for immediate "catch up"
0N/A * execution.
0N/A *
0N/A * <p>Fixed-rate execution is appropriate for recurring activities that
0N/A * are sensitive to <i>absolute</i> time, such as ringing a chime every
0N/A * hour on the hour, or running scheduled maintenance every day at a
0N/A * particular time. It is also appropriate for recurring activities
0N/A * where the total time to perform a fixed number of executions is
0N/A * important, such as a countdown timer that ticks once every second for
0N/A * ten seconds. Finally, fixed-rate execution is appropriate for
0N/A * scheduling multiple repeating timer tasks that must remain synchronized
0N/A * with respect to one another.
0N/A *
0N/A * @param task task to be scheduled.
0N/A * @param firstTime First time at which task is to be executed.
0N/A * @param period time in milliseconds between successive task executions.
0N/A * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
0N/A * {@code period <= 0}
0N/A * @throws IllegalStateException if task was already scheduled or
0N/A * cancelled, timer was cancelled, or timer thread terminated.
0N/A * @throws NullPointerException if {@code task} or {@code firstTime} is null
0N/A */
0N/A public void scheduleAtFixedRate(TimerTask task, Date firstTime,
0N/A long period) {
0N/A if (period <= 0)
0N/A throw new IllegalArgumentException("Non-positive period.");
0N/A sched(task, firstTime.getTime(), period);
0N/A }
0N/A
0N/A /**
0N/A * Schedule the specified timer task for execution at the specified
0N/A * time with the specified period, in milliseconds. If period is
0N/A * positive, the task is scheduled for repeated execution; if period is
0N/A * zero, the task is scheduled for one-time execution. Time is specified
0N/A * in Date.getTime() format. This method checks timer state, task state,
0N/A * and initial execution time, but not period.
0N/A *
0N/A * @throws IllegalArgumentException if <tt>time</tt> is negative.
0N/A * @throws IllegalStateException if task was already scheduled or
0N/A * cancelled, timer was cancelled, or timer thread terminated.
0N/A * @throws NullPointerException if {@code task} is null
0N/A */
0N/A private void sched(TimerTask task, long time, long period) {
0N/A if (time < 0)
0N/A throw new IllegalArgumentException("Illegal execution time.");
0N/A
479N/A // Constrain value of period sufficiently to prevent numeric
479N/A // overflow while still being effectively infinitely large.
479N/A if (Math.abs(period) > (Long.MAX_VALUE >> 1))
479N/A period >>= 1;
479N/A
0N/A synchronized(queue) {
0N/A if (!thread.newTasksMayBeScheduled)
0N/A throw new IllegalStateException("Timer already cancelled.");
0N/A
0N/A synchronized(task.lock) {
0N/A if (task.state != TimerTask.VIRGIN)
0N/A throw new IllegalStateException(
0N/A "Task already scheduled or cancelled");
0N/A task.nextExecutionTime = time;
0N/A task.period = period;
0N/A task.state = TimerTask.SCHEDULED;
0N/A }
0N/A
0N/A queue.add(task);
0N/A if (queue.getMin() == task)
0N/A queue.notify();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Terminates this timer, discarding any currently scheduled tasks.
0N/A * Does not interfere with a currently executing task (if it exists).
0N/A * Once a timer has been terminated, its execution thread terminates
0N/A * gracefully, and no more tasks may be scheduled on it.
0N/A *
0N/A * <p>Note that calling this method from within the run method of a
0N/A * timer task that was invoked by this timer absolutely guarantees that
0N/A * the ongoing task execution is the last task execution that will ever
0N/A * be performed by this timer.
0N/A *
0N/A * <p>This method may be called repeatedly; the second and subsequent
0N/A * calls have no effect.
0N/A */
0N/A public void cancel() {
0N/A synchronized(queue) {
0N/A thread.newTasksMayBeScheduled = false;
0N/A queue.clear();
0N/A queue.notify(); // In case queue was already empty.
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Removes all cancelled tasks from this timer's task queue. <i>Calling
0N/A * this method has no effect on the behavior of the timer</i>, but
0N/A * eliminates the references to the cancelled tasks from the queue.
0N/A * If there are no external references to these tasks, they become
0N/A * eligible for garbage collection.
0N/A *
0N/A * <p>Most programs will have no need to call this method.
0N/A * It is designed for use by the rare application that cancels a large
0N/A * number of tasks. Calling this method trades time for space: the
0N/A * runtime of the method may be proportional to n + c log n, where n
0N/A * is the number of tasks in the queue and c is the number of cancelled
0N/A * tasks.
0N/A *
0N/A * <p>Note that it is permissible to call this method from within a
0N/A * a task scheduled on this timer.
0N/A *
0N/A * @return the number of tasks removed from the queue.
0N/A * @since 1.5
0N/A */
0N/A public int purge() {
0N/A int result = 0;
0N/A
0N/A synchronized(queue) {
0N/A for (int i = queue.size(); i > 0; i--) {
0N/A if (queue.get(i).state == TimerTask.CANCELLED) {
0N/A queue.quickRemove(i);
0N/A result++;
0N/A }
0N/A }
0N/A
0N/A if (result != 0)
0N/A queue.heapify();
0N/A }
0N/A
0N/A return result;
0N/A }
0N/A}
0N/A
0N/A/**
0N/A * This "helper class" implements the timer's task execution thread, which
0N/A * waits for tasks on the timer queue, executions them when they fire,
0N/A * reschedules repeating tasks, and removes cancelled tasks and spent
0N/A * non-repeating tasks from the queue.
0N/A */
0N/Aclass TimerThread extends Thread {
0N/A /**
0N/A * This flag is set to false by the reaper to inform us that there
0N/A * are no more live references to our Timer object. Once this flag
0N/A * is true and there are no more tasks in our queue, there is no
0N/A * work left for us to do, so we terminate gracefully. Note that
0N/A * this field is protected by queue's monitor!
0N/A */
0N/A boolean newTasksMayBeScheduled = true;
0N/A
0N/A /**
0N/A * Our Timer's queue. We store this reference in preference to
0N/A * a reference to the Timer so the reference graph remains acyclic.
0N/A * Otherwise, the Timer would never be garbage-collected and this
0N/A * thread would never go away.
0N/A */
0N/A private TaskQueue queue;
0N/A
0N/A TimerThread(TaskQueue queue) {
0N/A this.queue = queue;
0N/A }
0N/A
0N/A public void run() {
0N/A try {
0N/A mainLoop();
0N/A } finally {
0N/A // Someone killed this Thread, behave as if Timer cancelled
0N/A synchronized(queue) {
0N/A newTasksMayBeScheduled = false;
0N/A queue.clear(); // Eliminate obsolete references
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * The main timer loop. (See class comment.)
0N/A */
0N/A private void mainLoop() {
0N/A while (true) {
0N/A try {
0N/A TimerTask task;
0N/A boolean taskFired;
0N/A synchronized(queue) {
0N/A // Wait for queue to become non-empty
0N/A while (queue.isEmpty() && newTasksMayBeScheduled)
0N/A queue.wait();
0N/A if (queue.isEmpty())
0N/A break; // Queue is empty and will forever remain; die
0N/A
0N/A // Queue nonempty; look at first evt and do the right thing
0N/A long currentTime, executionTime;
0N/A task = queue.getMin();
0N/A synchronized(task.lock) {
0N/A if (task.state == TimerTask.CANCELLED) {
0N/A queue.removeMin();
0N/A continue; // No action required, poll queue again
0N/A }
0N/A currentTime = System.currentTimeMillis();
0N/A executionTime = task.nextExecutionTime;
0N/A if (taskFired = (executionTime<=currentTime)) {
0N/A if (task.period == 0) { // Non-repeating, remove
0N/A queue.removeMin();
0N/A task.state = TimerTask.EXECUTED;
0N/A } else { // Repeating task, reschedule
0N/A queue.rescheduleMin(
0N/A task.period<0 ? currentTime - task.period
0N/A : executionTime + task.period);
0N/A }
0N/A }
0N/A }
0N/A if (!taskFired) // Task hasn't yet fired; wait
0N/A queue.wait(executionTime - currentTime);
0N/A }
0N/A if (taskFired) // Task fired; run it, holding no locks
0N/A task.run();
0N/A } catch(InterruptedException e) {
0N/A }
0N/A }
0N/A }
0N/A}
0N/A
0N/A/**
0N/A * This class represents a timer task queue: a priority queue of TimerTasks,
0N/A * ordered on nextExecutionTime. Each Timer object has one of these, which it
0N/A * shares with its TimerThread. Internally this class uses a heap, which
0N/A * offers log(n) performance for the add, removeMin and rescheduleMin
0N/A * operations, and constant time performance for the getMin operation.
0N/A */
0N/Aclass TaskQueue {
0N/A /**
0N/A * Priority queue represented as a balanced binary heap: the two children
0N/A * of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is
0N/A * ordered on the nextExecutionTime field: The TimerTask with the lowest
0N/A * nextExecutionTime is in queue[1] (assuming the queue is nonempty). For
0N/A * each node n in the heap, and each descendant of n, d,
0N/A * n.nextExecutionTime <= d.nextExecutionTime.
0N/A */
0N/A private TimerTask[] queue = new TimerTask[128];
0N/A
0N/A /**
0N/A * The number of tasks in the priority queue. (The tasks are stored in
0N/A * queue[1] up to queue[size]).
0N/A */
0N/A private int size = 0;
0N/A
0N/A /**
0N/A * Returns the number of tasks currently on the queue.
0N/A */
0N/A int size() {
0N/A return size;
0N/A }
0N/A
0N/A /**
0N/A * Adds a new task to the priority queue.
0N/A */
0N/A void add(TimerTask task) {
0N/A // Grow backing store if necessary
0N/A if (size + 1 == queue.length)
0N/A queue = Arrays.copyOf(queue, 2*queue.length);
0N/A
0N/A queue[++size] = task;
0N/A fixUp(size);
0N/A }
0N/A
0N/A /**
0N/A * Return the "head task" of the priority queue. (The head task is an
0N/A * task with the lowest nextExecutionTime.)
0N/A */
0N/A TimerTask getMin() {
0N/A return queue[1];
0N/A }
0N/A
0N/A /**
0N/A * Return the ith task in the priority queue, where i ranges from 1 (the
0N/A * head task, which is returned by getMin) to the number of tasks on the
0N/A * queue, inclusive.
0N/A */
0N/A TimerTask get(int i) {
0N/A return queue[i];
0N/A }
0N/A
0N/A /**
0N/A * Remove the head task from the priority queue.
0N/A */
0N/A void removeMin() {
0N/A queue[1] = queue[size];
0N/A queue[size--] = null; // Drop extra reference to prevent memory leak
0N/A fixDown(1);
0N/A }
0N/A
0N/A /**
0N/A * Removes the ith element from queue without regard for maintaining
0N/A * the heap invariant. Recall that queue is one-based, so
0N/A * 1 <= i <= size.
0N/A */
0N/A void quickRemove(int i) {
0N/A assert i <= size;
0N/A
0N/A queue[i] = queue[size];
0N/A queue[size--] = null; // Drop extra ref to prevent memory leak
0N/A }
0N/A
0N/A /**
0N/A * Sets the nextExecutionTime associated with the head task to the
0N/A * specified value, and adjusts priority queue accordingly.
0N/A */
0N/A void rescheduleMin(long newTime) {
0N/A queue[1].nextExecutionTime = newTime;
0N/A fixDown(1);
0N/A }
0N/A
0N/A /**
0N/A * Returns true if the priority queue contains no elements.
0N/A */
0N/A boolean isEmpty() {
0N/A return size==0;
0N/A }
0N/A
0N/A /**
0N/A * Removes all elements from the priority queue.
0N/A */
0N/A void clear() {
0N/A // Null out task references to prevent memory leak
0N/A for (int i=1; i<=size; i++)
0N/A queue[i] = null;
0N/A
0N/A size = 0;
0N/A }
0N/A
0N/A /**
0N/A * Establishes the heap invariant (described above) assuming the heap
0N/A * satisfies the invariant except possibly for the leaf-node indexed by k
0N/A * (which may have a nextExecutionTime less than its parent's).
0N/A *
0N/A * This method functions by "promoting" queue[k] up the hierarchy
0N/A * (by swapping it with its parent) repeatedly until queue[k]'s
0N/A * nextExecutionTime is greater than or equal to that of its parent.
0N/A */
0N/A private void fixUp(int k) {
0N/A while (k > 1) {
0N/A int j = k >> 1;
0N/A if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
0N/A break;
0N/A TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
0N/A k = j;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Establishes the heap invariant (described above) in the subtree
0N/A * rooted at k, which is assumed to satisfy the heap invariant except
0N/A * possibly for node k itself (which may have a nextExecutionTime greater
0N/A * than its children's).
0N/A *
0N/A * This method functions by "demoting" queue[k] down the hierarchy
0N/A * (by swapping it with its smaller child) repeatedly until queue[k]'s
0N/A * nextExecutionTime is less than or equal to those of its children.
0N/A */
0N/A private void fixDown(int k) {
0N/A int j;
0N/A while ((j = k << 1) <= size && j > 0) {
0N/A if (j < size &&
0N/A queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
0N/A j++; // j indexes smallest kid
0N/A if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
0N/A break;
0N/A TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
0N/A k = j;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Establishes the heap invariant (described above) in the entire tree,
0N/A * assuming nothing about the order of the elements prior to the call.
0N/A */
0N/A void heapify() {
0N/A for (int i = size/2; i >= 1; i--)
0N/A fixDown(i);
0N/A }
0N/A}