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