History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/util/Timer.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/util/Timer.java+720−0
@@ -0,0 +1,720 @@
1+/*
2+ * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.util;
27+import java.util.Date;
28+import java.util.concurrent.atomic.AtomicInteger;
29+
30+/**
31+ * A facility for threads to schedule tasks for future execution in a
32+ * background thread. Tasks may be scheduled for one-time execution, or for
33+ * repeated execution at regular intervals.
34+ *
35+ * <p>Corresponding to each <tt>Timer</tt> object is a single background
36+ * thread that is used to execute all of the timer's tasks, sequentially.
37+ * Timer tasks should complete quickly. If a timer task takes excessive time
38+ * to complete, it "hogs" the timer's task execution thread. This can, in
39+ * turn, delay the execution of subsequent tasks, which may "bunch up" and
40+ * execute in rapid succession when (and if) the offending task finally
41+ * completes.
42+ *
43+ * <p>After the last live reference to a <tt>Timer</tt> object goes away
44+ * <i>and</i> all outstanding tasks have completed execution, the timer's task
45+ * execution thread terminates gracefully (and becomes subject to garbage
46+ * collection). However, this can take arbitrarily long to occur. By
47+ * default, the task execution thread does not run as a <i>daemon thread</i>,
48+ * so it is capable of keeping an application from terminating. If a caller
49+ * wants to terminate a timer's task execution thread rapidly, the caller
50+ * should invoke the timer's <tt>cancel</tt> method.
51+ *
52+ * <p>If the timer's task execution thread terminates unexpectedly, for
53+ * example, because its <tt>stop</tt> method is invoked, any further
54+ * attempt to schedule a task on the timer will result in an
55+ * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
56+ * method had been invoked.
57+ *
58+ * <p>This class is thread-safe: multiple threads can share a single
59+ * <tt>Timer</tt> object without the need for external synchronization.
60+ *
61+ * <p>This class does <i>not</i> offer real-time guarantees: it schedules
62+ * tasks using the <tt>Object.wait(long)</tt> method.
63+ *
64+ * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
65+ * one of the concurrency utilities therein is the {@link
66+ * java.util.concurrent.ScheduledThreadPoolExecutor
67+ * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
68+ * executing tasks at a given rate or delay. It is effectively a more
69+ * versatile replacement for the {@code Timer}/{@code TimerTask}
70+ * combination, as it allows multiple service threads, accepts various
71+ * time units, and doesn't require subclassing {@code TimerTask} (just
72+ * implement {@code Runnable}). Configuring {@code
73+ * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
74+ * {@code Timer}.
75+ *
76+ * <p>Implementation note: This class scales to large numbers of concurrently
77+ * scheduled tasks (thousands should present no problem). Internally,
78+ * it uses a binary heap to represent its task queue, so the cost to schedule
79+ * a task is O(log n), where n is the number of concurrently scheduled tasks.
80+ *
81+ * <p>Implementation note: All constructors start a timer thread.
82+ *
83+ * @author Josh Bloch
84+ * @see TimerTask
85+ * @see Object#wait(long)
86+ * @since 1.3
87+ */
88+
89+public class Timer {
90+ /**
91+ * The timer task queue. This data structure is shared with the timer
92+ * thread. The timer produces tasks, via its various schedule calls,
93+ * and the timer thread consumes, executing timer tasks as appropriate,
94+ * and removing them from the queue when they're obsolete.
95+ */
96+ private final TaskQueue queue = new TaskQueue();
97+
98+ /**
99+ * The timer thread.
100+ */
101+ private final TimerThread thread = new TimerThread(queue);
102+
103+ /**
104+ * This object causes the timer's task execution thread to exit
105+ * gracefully when there are no live references to the Timer object and no
106+ * tasks in the timer queue. It is used in preference to a finalizer on
107+ * Timer as such a finalizer would be susceptible to a subclass's
108+ * finalizer forgetting to call it.
109+ */
110+ private final Object threadReaper = new Object() {
111+ protected void finalize() throws Throwable {
112+ synchronized(queue) {
113+ thread.newTasksMayBeScheduled = false;
114+ queue.notify(); // In case queue is empty.
115+ }
116+ }
117+ };
118+
119+ /**
120+ * This ID is used to generate thread names.
121+ */
122+ private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
123+ private static int serialNumber() {
124+ return nextSerialNumber.getAndIncrement();
125+ }
126+
127+ /**
128+ * Creates a new timer. The associated thread does <i>not</i>
129+ * {@linkplain Thread#setDaemon run as a daemon}.
130+ */
131+ public Timer() {
132+ this("Timer-" + serialNumber());
133+ }
134+
135+ /**
136+ * Creates a new timer whose associated thread may be specified to
137+ * {@linkplain Thread#setDaemon run as a daemon}.
138+ * A daemon thread is called for if the timer will be used to
139+ * schedule repeating "maintenance activities", which must be
140+ * performed as long as the application is running, but should not
141+ * prolong the lifetime of the application.
142+ *
143+ * @param isDaemon true if the associated thread should run as a daemon.
144+ */
145+ public Timer(boolean isDaemon) {
146+ this("Timer-" + serialNumber(), isDaemon);
147+ }
148+
149+ /**
150+ * Creates a new timer whose associated thread has the specified name.
151+ * The associated thread does <i>not</i>
152+ * {@linkplain Thread#setDaemon run as a daemon}.
153+ *
154+ * @param name the name of the associated thread
155+ * @throws NullPointerException if {@code name} is null
156+ * @since 1.5
157+ */
158+ public Timer(String name) {
159+ thread.setName(name);
160+ thread.start();
161+ }
162+
163+ /**
164+ * Creates a new timer whose associated thread has the specified name,
165+ * and may be specified to
166+ * {@linkplain Thread#setDaemon run as a daemon}.
167+ *
168+ * @param name the name of the associated thread
169+ * @param isDaemon true if the associated thread should run as a daemon
170+ * @throws NullPointerException if {@code name} is null
171+ * @since 1.5
172+ */
173+ public Timer(String name, boolean isDaemon) {
174+ thread.setName(name);
175+ thread.setDaemon(isDaemon);
176+ thread.start();
177+ }
178+
179+ /**
180+ * Schedules the specified task for execution after the specified delay.
181+ *
182+ * @param task task to be scheduled.
183+ * @param delay delay in milliseconds before task is to be executed.
184+ * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
185+ * <tt>delay + System.currentTimeMillis()</tt> is negative.
186+ * @throws IllegalStateException if task was already scheduled or
187+ * cancelled, timer was cancelled, or timer thread terminated.
188+ * @throws NullPointerException if {@code task} is null
189+ */
190+ public void schedule(TimerTask task, long delay) {
191+ if (delay < 0)
192+ throw new IllegalArgumentException("Negative delay.");
193+ sched(task, System.currentTimeMillis()+delay, 0);
194+ }
195+
196+ /**
197+ * Schedules the specified task for execution at the specified time. If
198+ * the time is in the past, the task is scheduled for immediate execution.
199+ *
200+ * @param task task to be scheduled.
201+ * @param time time at which task is to be executed.
202+ * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
203+ * @throws IllegalStateException if task was already scheduled or
204+ * cancelled, timer was cancelled, or timer thread terminated.
205+ * @throws NullPointerException if {@code task} or {@code time} is null
206+ */
207+ public void schedule(TimerTask task, Date time) {
208+ sched(task, time.getTime(), 0);
209+ }
210+
211+ /**
212+ * Schedules the specified task for repeated <i>fixed-delay execution</i>,
213+ * beginning after the specified delay. Subsequent executions take place
214+ * at approximately regular intervals separated by the specified period.
215+ *
216+ * <p>In fixed-delay execution, each execution is scheduled relative to
217+ * the actual execution time of the previous execution. If an execution
218+ * is delayed for any reason (such as garbage collection or other
219+ * background activity), subsequent executions will be delayed as well.
220+ * In the long run, the frequency of execution will generally be slightly
221+ * lower than the reciprocal of the specified period (assuming the system
222+ * clock underlying <tt>Object.wait(long)</tt> is accurate).
223+ *
224+ * <p>Fixed-delay execution is appropriate for recurring activities
225+ * that require "smoothness." In other words, it is appropriate for
226+ * activities where it is more important to keep the frequency accurate
227+ * in the short run than in the long run. This includes most animation
228+ * tasks, such as blinking a cursor at regular intervals. It also includes
229+ * tasks wherein regular activity is performed in response to human
230+ * input, such as automatically repeating a character as long as a key
231+ * is held down.
232+ *
233+ * @param task task to be scheduled.
234+ * @param delay delay in milliseconds before task is to be executed.
235+ * @param period time in milliseconds between successive task executions.
236+ * @throws IllegalArgumentException if {@code delay < 0}, or
237+ * {@code delay + System.currentTimeMillis() < 0}, or
238+ * {@code period <= 0}
239+ * @throws IllegalStateException if task was already scheduled or
240+ * cancelled, timer was cancelled, or timer thread terminated.
241+ * @throws NullPointerException if {@code task} is null
242+ */
243+ public void schedule(TimerTask task, long delay, long period) {
244+ if (delay < 0)
245+ throw new IllegalArgumentException("Negative delay.");
246+ if (period <= 0)
247+ throw new IllegalArgumentException("Non-positive period.");
248+ sched(task, System.currentTimeMillis()+delay, -period);
249+ }
250+
251+ /**
252+ * Schedules the specified task for repeated <i>fixed-delay execution</i>,
253+ * beginning at the specified time. Subsequent executions take place at
254+ * approximately regular intervals, separated by the specified period.
255+ *
256+ * <p>In fixed-delay execution, each execution is scheduled relative to
257+ * the actual execution time of the previous execution. If an execution
258+ * is delayed for any reason (such as garbage collection or other
259+ * background activity), subsequent executions will be delayed as well.
260+ * In the long run, the frequency of execution will generally be slightly
261+ * lower than the reciprocal of the specified period (assuming the system
262+ * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
263+ * consequence of the above, if the scheduled first time is in the past,
264+ * it is scheduled for immediate execution.
265+ *
266+ * <p>Fixed-delay execution is appropriate for recurring activities
267+ * that require "smoothness." In other words, it is appropriate for
268+ * activities where it is more important to keep the frequency accurate
269+ * in the short run than in the long run. This includes most animation
270+ * tasks, such as blinking a cursor at regular intervals. It also includes
271+ * tasks wherein regular activity is performed in response to human
272+ * input, such as automatically repeating a character as long as a key
273+ * is held down.
274+ *
275+ * @param task task to be scheduled.
276+ * @param firstTime First time at which task is to be executed.
277+ * @param period time in milliseconds between successive task executions.
278+ * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
279+ * {@code period <= 0}
280+ * @throws IllegalStateException if task was already scheduled or
281+ * cancelled, timer was cancelled, or timer thread terminated.
282+ * @throws NullPointerException if {@code task} or {@code firstTime} is null
283+ */
284+ public void schedule(TimerTask task, Date firstTime, long period) {
285+ if (period <= 0)
286+ throw new IllegalArgumentException("Non-positive period.");
287+ sched(task, firstTime.getTime(), -period);
288+ }
289+
290+ /**
291+ * Schedules the specified task for repeated <i>fixed-rate execution</i>,
292+ * beginning after the specified delay. Subsequent executions take place
293+ * at approximately regular intervals, separated by the specified period.
294+ *
295+ * <p>In fixed-rate execution, each execution is scheduled relative to the
296+ * scheduled execution time of the initial execution. If an execution is
297+ * delayed for any reason (such as garbage collection or other background
298+ * activity), two or more executions will occur in rapid succession to
299+ * "catch up." In the long run, the frequency of execution will be
300+ * exactly the reciprocal of the specified period (assuming the system
301+ * clock underlying <tt>Object.wait(long)</tt> is accurate).
302+ *
303+ * <p>Fixed-rate execution is appropriate for recurring activities that
304+ * are sensitive to <i>absolute</i> time, such as ringing a chime every
305+ * hour on the hour, or running scheduled maintenance every day at a
306+ * particular time. It is also appropriate for recurring activities
307+ * where the total time to perform a fixed number of executions is
308+ * important, such as a countdown timer that ticks once every second for
309+ * ten seconds. Finally, fixed-rate execution is appropriate for
310+ * scheduling multiple repeating timer tasks that must remain synchronized
311+ * with respect to one another.
312+ *
313+ * @param task task to be scheduled.
314+ * @param delay delay in milliseconds before task is to be executed.
315+ * @param period time in milliseconds between successive task executions.
316+ * @throws IllegalArgumentException if {@code delay < 0}, or
317+ * {@code delay + System.currentTimeMillis() < 0}, or
318+ * {@code period <= 0}
319+ * @throws IllegalStateException if task was already scheduled or
320+ * cancelled, timer was cancelled, or timer thread terminated.
321+ * @throws NullPointerException if {@code task} is null
322+ */
323+ public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
324+ if (delay < 0)
325+ throw new IllegalArgumentException("Negative delay.");
326+ if (period <= 0)
327+ throw new IllegalArgumentException("Non-positive period.");
328+ sched(task, System.currentTimeMillis()+delay, period);
329+ }
330+
331+ /**
332+ * Schedules the specified task for repeated <i>fixed-rate execution</i>,
333+ * beginning at the specified time. Subsequent executions take place at
334+ * approximately regular intervals, separated by the specified period.
335+ *
336+ * <p>In fixed-rate execution, each execution is scheduled relative to the
337+ * scheduled execution time of the initial execution. If an execution is
338+ * delayed for any reason (such as garbage collection or other background
339+ * activity), two or more executions will occur in rapid succession to
340+ * "catch up." In the long run, the frequency of execution will be
341+ * exactly the reciprocal of the specified period (assuming the system
342+ * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
343+ * consequence of the above, if the scheduled first time is in the past,
344+ * then any "missed" executions will be scheduled for immediate "catch up"
345+ * execution.
346+ *
347+ * <p>Fixed-rate execution is appropriate for recurring activities that
348+ * are sensitive to <i>absolute</i> time, such as ringing a chime every
349+ * hour on the hour, or running scheduled maintenance every day at a
350+ * particular time. It is also appropriate for recurring activities
351+ * where the total time to perform a fixed number of executions is
352+ * important, such as a countdown timer that ticks once every second for
353+ * ten seconds. Finally, fixed-rate execution is appropriate for
354+ * scheduling multiple repeating timer tasks that must remain synchronized
355+ * with respect to one another.
356+ *
357+ * @param task task to be scheduled.
358+ * @param firstTime First time at which task is to be executed.
359+ * @param period time in milliseconds between successive task executions.
360+ * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
361+ * {@code period <= 0}
362+ * @throws IllegalStateException if task was already scheduled or
363+ * cancelled, timer was cancelled, or timer thread terminated.
364+ * @throws NullPointerException if {@code task} or {@code firstTime} is null
365+ */
366+ public void scheduleAtFixedRate(TimerTask task, Date firstTime,
367+ long period) {
368+ if (period <= 0)
369+ throw new IllegalArgumentException("Non-positive period.");
370+ sched(task, firstTime.getTime(), period);
371+ }
372+
373+ /**
374+ * Schedule the specified timer task for execution at the specified
375+ * time with the specified period, in milliseconds. If period is
376+ * positive, the task is scheduled for repeated execution; if period is
377+ * zero, the task is scheduled for one-time execution. Time is specified
378+ * in Date.getTime() format. This method checks timer state, task state,
379+ * and initial execution time, but not period.
380+ *
381+ * @throws IllegalArgumentException if <tt>time</tt> is negative.
382+ * @throws IllegalStateException if task was already scheduled or
383+ * cancelled, timer was cancelled, or timer thread terminated.
384+ * @throws NullPointerException if {@code task} is null
385+ */
386+ private void sched(TimerTask task, long time, long period) {
387+ if (time < 0)
388+ throw new IllegalArgumentException("Illegal execution time.");
389+
390+ // Constrain value of period sufficiently to prevent numeric
391+ // overflow while still being effectively infinitely large.
392+ if (Math.abs(period) > (Long.MAX_VALUE >> 1))
393+ period >>= 1;
394+
395+ synchronized(queue) {
396+ if (!thread.newTasksMayBeScheduled)
397+ throw new IllegalStateException("Timer already cancelled.");
398+
399+ synchronized(task.lock) {
400+ if (task.state != TimerTask.VIRGIN)
401+ throw new IllegalStateException(
402+ "Task already scheduled or cancelled");
403+ task.nextExecutionTime = time;
404+ task.period = period;
405+ task.state = TimerTask.SCHEDULED;
406+ }
407+
408+ queue.add(task);
409+ if (queue.getMin() == task)
410+ queue.notify();
411+ }
412+ }
413+
414+ /**
415+ * Terminates this timer, discarding any currently scheduled tasks.
416+ * Does not interfere with a currently executing task (if it exists).
417+ * Once a timer has been terminated, its execution thread terminates
418+ * gracefully, and no more tasks may be scheduled on it.
419+ *
420+ * <p>Note that calling this method from within the run method of a
421+ * timer task that was invoked by this timer absolutely guarantees that
422+ * the ongoing task execution is the last task execution that will ever
423+ * be performed by this timer.
424+ *
425+ * <p>This method may be called repeatedly; the second and subsequent
426+ * calls have no effect.
427+ */
428+ public void cancel() {
429+ synchronized(queue) {
430+ thread.newTasksMayBeScheduled = false;
431+ queue.clear();
432+ queue.notify(); // In case queue was already empty.
433+ }
434+ }
435+
436+ /**
437+ * Removes all cancelled tasks from this timer's task queue. <i>Calling
438+ * this method has no effect on the behavior of the timer</i>, but
439+ * eliminates the references to the cancelled tasks from the queue.
440+ * If there are no external references to these tasks, they become
441+ * eligible for garbage collection.
442+ *
443+ * <p>Most programs will have no need to call this method.
444+ * It is designed for use by the rare application that cancels a large
445+ * number of tasks. Calling this method trades time for space: the
446+ * runtime of the method may be proportional to n + c log n, where n
447+ * is the number of tasks in the queue and c is the number of cancelled
448+ * tasks.
449+ *
450+ * <p>Note that it is permissible to call this method from within a
451+ * a task scheduled on this timer.
452+ *
453+ * @return the number of tasks removed from the queue.
454+ * @since 1.5
455+ */
456+ public int purge() {
457+ int result = 0;
458+
459+ synchronized(queue) {
460+ for (int i = queue.size(); i > 0; i--) {
461+ if (queue.get(i).state == TimerTask.CANCELLED) {
462+ queue.quickRemove(i);
463+ result++;
464+ }
465+ }
466+
467+ if (result != 0)
468+ queue.heapify();
469+ }
470+
471+ return result;
472+ }
473+}
474+
475+/**
476+ * This "helper class" implements the timer's task execution thread, which
477+ * waits for tasks on the timer queue, executions them when they fire,
478+ * reschedules repeating tasks, and removes cancelled tasks and spent
479+ * non-repeating tasks from the queue.
480+ */
481+class TimerThread extends Thread {
482+ /**
483+ * This flag is set to false by the reaper to inform us that there
484+ * are no more live references to our Timer object. Once this flag
485+ * is true and there are no more tasks in our queue, there is no
486+ * work left for us to do, so we terminate gracefully. Note that
487+ * this field is protected by queue's monitor!
488+ */
489+ boolean newTasksMayBeScheduled = true;
490+
491+ /**
492+ * Our Timer's queue. We store this reference in preference to
493+ * a reference to the Timer so the reference graph remains acyclic.
494+ * Otherwise, the Timer would never be garbage-collected and this
495+ * thread would never go away.
496+ */
497+ private TaskQueue queue;
498+
499+ TimerThread(TaskQueue queue) {
500+ this.queue = queue;
501+ }
502+
503+ public void run() {
504+ try {
505+ mainLoop();
506+ } finally {
507+ // Someone killed this Thread, behave as if Timer cancelled
508+ synchronized(queue) {
509+ newTasksMayBeScheduled = false;
510+ queue.clear(); // Eliminate obsolete references
511+ }
512+ }
513+ }
514+
515+ /**
516+ * The main timer loop. (See class comment.)
517+ */
518+ private void mainLoop() {
519+ while (true) {
520+ try {
521+ TimerTask task;
522+ boolean taskFired;
523+ synchronized(queue) {
524+ // Wait for queue to become non-empty
525+ while (queue.isEmpty() && newTasksMayBeScheduled)
526+ queue.wait();
527+ if (queue.isEmpty())
528+ break; // Queue is empty and will forever remain; die
529+
530+ // Queue nonempty; look at first evt and do the right thing
531+ long currentTime, executionTime;
532+ task = queue.getMin();
533+ synchronized(task.lock) {
534+ if (task.state == TimerTask.CANCELLED) {
535+ queue.removeMin();
536+ continue; // No action required, poll queue again
537+ }
538+ currentTime = System.currentTimeMillis();
539+ executionTime = task.nextExecutionTime;
540+ if (taskFired = (executionTime<=currentTime)) {
541+ if (task.period == 0) { // Non-repeating, remove
542+ queue.removeMin();
543+ task.state = TimerTask.EXECUTED;
544+ } else { // Repeating task, reschedule
545+ queue.rescheduleMin(
546+ task.period<0 ? currentTime - task.period
547+ : executionTime + task.period);
548+ }
549+ }
550+ }
551+ if (!taskFired) // Task hasn't yet fired; wait
552+ queue.wait(executionTime - currentTime);
553+ }
554+ if (taskFired) // Task fired; run it, holding no locks
555+ task.run();
556+ } catch(InterruptedException e) {
557+ }
558+ }
559+ }
560+}
561+
562+/**
563+ * This class represents a timer task queue: a priority queue of TimerTasks,
564+ * ordered on nextExecutionTime. Each Timer object has one of these, which it
565+ * shares with its TimerThread. Internally this class uses a heap, which
566+ * offers log(n) performance for the add, removeMin and rescheduleMin
567+ * operations, and constant time performance for the getMin operation.
568+ */
569+class TaskQueue {
570+ /**
571+ * Priority queue represented as a balanced binary heap: the two children
572+ * of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is
573+ * ordered on the nextExecutionTime field: The TimerTask with the lowest
574+ * nextExecutionTime is in queue[1] (assuming the queue is nonempty). For
575+ * each node n in the heap, and each descendant of n, d,
576+ * n.nextExecutionTime <= d.nextExecutionTime.
577+ */
578+ private TimerTask[] queue = new TimerTask[128];
579+
580+ /**
581+ * The number of tasks in the priority queue. (The tasks are stored in
582+ * queue[1] up to queue[size]).
583+ */
584+ private int size = 0;
585+
586+ /**
587+ * Returns the number of tasks currently on the queue.
588+ */
589+ int size() {
590+ return size;
591+ }
592+
593+ /**
594+ * Adds a new task to the priority queue.
595+ */
596+ void add(TimerTask task) {
597+ // Grow backing store if necessary
598+ if (size + 1 == queue.length)
599+ queue = Arrays.copyOf(queue, 2*queue.length);
600+
601+ queue[++size] = task;
602+ fixUp(size);
603+ }
604+
605+ /**
606+ * Return the "head task" of the priority queue. (The head task is an
607+ * task with the lowest nextExecutionTime.)
608+ */
609+ TimerTask getMin() {
610+ return queue[1];
611+ }
612+
613+ /**
614+ * Return the ith task in the priority queue, where i ranges from 1 (the
615+ * head task, which is returned by getMin) to the number of tasks on the
616+ * queue, inclusive.
617+ */
618+ TimerTask get(int i) {
619+ return queue[i];
620+ }
621+
622+ /**
623+ * Remove the head task from the priority queue.
624+ */
625+ void removeMin() {
626+ queue[1] = queue[size];
627+ queue[size--] = null; // Drop extra reference to prevent memory leak
628+ fixDown(1);
629+ }
630+
631+ /**
632+ * Removes the ith element from queue without regard for maintaining
633+ * the heap invariant. Recall that queue is one-based, so
634+ * 1 <= i <= size.
635+ */
636+ void quickRemove(int i) {
637+ assert i <= size;
638+
639+ queue[i] = queue[size];
640+ queue[size--] = null; // Drop extra ref to prevent memory leak
641+ }
642+
643+ /**
644+ * Sets the nextExecutionTime associated with the head task to the
645+ * specified value, and adjusts priority queue accordingly.
646+ */
647+ void rescheduleMin(long newTime) {
648+ queue[1].nextExecutionTime = newTime;
649+ fixDown(1);
650+ }
651+
652+ /**
653+ * Returns true if the priority queue contains no elements.
654+ */
655+ boolean isEmpty() {
656+ return size==0;
657+ }
658+
659+ /**
660+ * Removes all elements from the priority queue.
661+ */
662+ void clear() {
663+ // Null out task references to prevent memory leak
664+ for (int i=1; i<=size; i++)
665+ queue[i] = null;
666+
667+ size = 0;
668+ }
669+
670+ /**
671+ * Establishes the heap invariant (described above) assuming the heap
672+ * satisfies the invariant except possibly for the leaf-node indexed by k
673+ * (which may have a nextExecutionTime less than its parent's).
674+ *
675+ * This method functions by "promoting" queue[k] up the hierarchy
676+ * (by swapping it with its parent) repeatedly until queue[k]'s
677+ * nextExecutionTime is greater than or equal to that of its parent.
678+ */
679+ private void fixUp(int k) {
680+ while (k > 1) {
681+ int j = k >> 1;
682+ if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
683+ break;
684+ TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
685+ k = j;
686+ }
687+ }
688+
689+ /**
690+ * Establishes the heap invariant (described above) in the subtree
691+ * rooted at k, which is assumed to satisfy the heap invariant except
692+ * possibly for node k itself (which may have a nextExecutionTime greater
693+ * than its children's).
694+ *
695+ * This method functions by "demoting" queue[k] down the hierarchy
696+ * (by swapping it with its smaller child) repeatedly until queue[k]'s
697+ * nextExecutionTime is less than or equal to those of its children.
698+ */
699+ private void fixDown(int k) {
700+ int j;
701+ while ((j = k << 1) <= size && j > 0) {
702+ if (j < size &&
703+ queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
704+ j++; // j indexes smallest kid
705+ if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
706+ break;
707+ TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
708+ k = j;
709+ }
710+ }
711+
712+ /**
713+ * Establishes the heap invariant (described above) in the entire tree,
714+ * assuming nothing about the order of the elements prior to the call.
715+ */
716+ void heapify() {
717+ for (int i = size/2; i >= 1; i--)
718+ fixDown(i);
719+ }
720+}