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