1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/util/Timer.java Sat Nov 02 16:43:48 2013 +0100
1.3 @@ -0,0 +1,720 @@
1.4 +/*
1.5 + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package java.util;
1.30 +import java.util.Date;
1.31 +import java.util.concurrent.atomic.AtomicInteger;
1.32 +
1.33 +/**
1.34 + * A facility for threads to schedule tasks for future execution in a
1.35 + * background thread. Tasks may be scheduled for one-time execution, or for
1.36 + * repeated execution at regular intervals.
1.37 + *
1.38 + * <p>Corresponding to each <tt>Timer</tt> object is a single background
1.39 + * thread that is used to execute all of the timer's tasks, sequentially.
1.40 + * Timer tasks should complete quickly. If a timer task takes excessive time
1.41 + * to complete, it "hogs" the timer's task execution thread. This can, in
1.42 + * turn, delay the execution of subsequent tasks, which may "bunch up" and
1.43 + * execute in rapid succession when (and if) the offending task finally
1.44 + * completes.
1.45 + *
1.46 + * <p>After the last live reference to a <tt>Timer</tt> object goes away
1.47 + * <i>and</i> all outstanding tasks have completed execution, the timer's task
1.48 + * execution thread terminates gracefully (and becomes subject to garbage
1.49 + * collection). However, this can take arbitrarily long to occur. By
1.50 + * default, the task execution thread does not run as a <i>daemon thread</i>,
1.51 + * so it is capable of keeping an application from terminating. If a caller
1.52 + * wants to terminate a timer's task execution thread rapidly, the caller
1.53 + * should invoke the timer's <tt>cancel</tt> method.
1.54 + *
1.55 + * <p>If the timer's task execution thread terminates unexpectedly, for
1.56 + * example, because its <tt>stop</tt> method is invoked, any further
1.57 + * attempt to schedule a task on the timer will result in an
1.58 + * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
1.59 + * method had been invoked.
1.60 + *
1.61 + * <p>This class is thread-safe: multiple threads can share a single
1.62 + * <tt>Timer</tt> object without the need for external synchronization.
1.63 + *
1.64 + * <p>This class does <i>not</i> offer real-time guarantees: it schedules
1.65 + * tasks using the <tt>Object.wait(long)</tt> method.
1.66 + *
1.67 + * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
1.68 + * one of the concurrency utilities therein is the {@link
1.69 + * java.util.concurrent.ScheduledThreadPoolExecutor
1.70 + * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
1.71 + * executing tasks at a given rate or delay. It is effectively a more
1.72 + * versatile replacement for the {@code Timer}/{@code TimerTask}
1.73 + * combination, as it allows multiple service threads, accepts various
1.74 + * time units, and doesn't require subclassing {@code TimerTask} (just
1.75 + * implement {@code Runnable}). Configuring {@code
1.76 + * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
1.77 + * {@code Timer}.
1.78 + *
1.79 + * <p>Implementation note: This class scales to large numbers of concurrently
1.80 + * scheduled tasks (thousands should present no problem). Internally,
1.81 + * it uses a binary heap to represent its task queue, so the cost to schedule
1.82 + * a task is O(log n), where n is the number of concurrently scheduled tasks.
1.83 + *
1.84 + * <p>Implementation note: All constructors start a timer thread.
1.85 + *
1.86 + * @author Josh Bloch
1.87 + * @see TimerTask
1.88 + * @see Object#wait(long)
1.89 + * @since 1.3
1.90 + */
1.91 +
1.92 +public class Timer {
1.93 + /**
1.94 + * The timer task queue. This data structure is shared with the timer
1.95 + * thread. The timer produces tasks, via its various schedule calls,
1.96 + * and the timer thread consumes, executing timer tasks as appropriate,
1.97 + * and removing them from the queue when they're obsolete.
1.98 + */
1.99 + private final TaskQueue queue = new TaskQueue();
1.100 +
1.101 + /**
1.102 + * The timer thread.
1.103 + */
1.104 + private final TimerThread thread = new TimerThread(queue);
1.105 +
1.106 + /**
1.107 + * This object causes the timer's task execution thread to exit
1.108 + * gracefully when there are no live references to the Timer object and no
1.109 + * tasks in the timer queue. It is used in preference to a finalizer on
1.110 + * Timer as such a finalizer would be susceptible to a subclass's
1.111 + * finalizer forgetting to call it.
1.112 + */
1.113 + private final Object threadReaper = new Object() {
1.114 + protected void finalize() throws Throwable {
1.115 + synchronized(queue) {
1.116 + thread.newTasksMayBeScheduled = false;
1.117 + queue.notify(); // In case queue is empty.
1.118 + }
1.119 + }
1.120 + };
1.121 +
1.122 + /**
1.123 + * This ID is used to generate thread names.
1.124 + */
1.125 + private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
1.126 + private static int serialNumber() {
1.127 + return nextSerialNumber.getAndIncrement();
1.128 + }
1.129 +
1.130 + /**
1.131 + * Creates a new timer. The associated thread does <i>not</i>
1.132 + * {@linkplain Thread#setDaemon run as a daemon}.
1.133 + */
1.134 + public Timer() {
1.135 + this("Timer-" + serialNumber());
1.136 + }
1.137 +
1.138 + /**
1.139 + * Creates a new timer whose associated thread may be specified to
1.140 + * {@linkplain Thread#setDaemon run as a daemon}.
1.141 + * A daemon thread is called for if the timer will be used to
1.142 + * schedule repeating "maintenance activities", which must be
1.143 + * performed as long as the application is running, but should not
1.144 + * prolong the lifetime of the application.
1.145 + *
1.146 + * @param isDaemon true if the associated thread should run as a daemon.
1.147 + */
1.148 + public Timer(boolean isDaemon) {
1.149 + this("Timer-" + serialNumber(), isDaemon);
1.150 + }
1.151 +
1.152 + /**
1.153 + * Creates a new timer whose associated thread has the specified name.
1.154 + * The associated thread does <i>not</i>
1.155 + * {@linkplain Thread#setDaemon run as a daemon}.
1.156 + *
1.157 + * @param name the name of the associated thread
1.158 + * @throws NullPointerException if {@code name} is null
1.159 + * @since 1.5
1.160 + */
1.161 + public Timer(String name) {
1.162 + thread.setName(name);
1.163 + thread.start();
1.164 + }
1.165 +
1.166 + /**
1.167 + * Creates a new timer whose associated thread has the specified name,
1.168 + * and may be specified to
1.169 + * {@linkplain Thread#setDaemon run as a daemon}.
1.170 + *
1.171 + * @param name the name of the associated thread
1.172 + * @param isDaemon true if the associated thread should run as a daemon
1.173 + * @throws NullPointerException if {@code name} is null
1.174 + * @since 1.5
1.175 + */
1.176 + public Timer(String name, boolean isDaemon) {
1.177 + thread.setName(name);
1.178 + thread.setDaemon(isDaemon);
1.179 + thread.start();
1.180 + }
1.181 +
1.182 + /**
1.183 + * Schedules the specified task for execution after the specified delay.
1.184 + *
1.185 + * @param task task to be scheduled.
1.186 + * @param delay delay in milliseconds before task is to be executed.
1.187 + * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
1.188 + * <tt>delay + System.currentTimeMillis()</tt> is negative.
1.189 + * @throws IllegalStateException if task was already scheduled or
1.190 + * cancelled, timer was cancelled, or timer thread terminated.
1.191 + * @throws NullPointerException if {@code task} is null
1.192 + */
1.193 + public void schedule(TimerTask task, long delay) {
1.194 + if (delay < 0)
1.195 + throw new IllegalArgumentException("Negative delay.");
1.196 + sched(task, System.currentTimeMillis()+delay, 0);
1.197 + }
1.198 +
1.199 + /**
1.200 + * Schedules the specified task for execution at the specified time. If
1.201 + * the time is in the past, the task is scheduled for immediate execution.
1.202 + *
1.203 + * @param task task to be scheduled.
1.204 + * @param time time at which task is to be executed.
1.205 + * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
1.206 + * @throws IllegalStateException if task was already scheduled or
1.207 + * cancelled, timer was cancelled, or timer thread terminated.
1.208 + * @throws NullPointerException if {@code task} or {@code time} is null
1.209 + */
1.210 + public void schedule(TimerTask task, Date time) {
1.211 + sched(task, time.getTime(), 0);
1.212 + }
1.213 +
1.214 + /**
1.215 + * Schedules the specified task for repeated <i>fixed-delay execution</i>,
1.216 + * beginning after the specified delay. Subsequent executions take place
1.217 + * at approximately regular intervals separated by the specified period.
1.218 + *
1.219 + * <p>In fixed-delay execution, each execution is scheduled relative to
1.220 + * the actual execution time of the previous execution. If an execution
1.221 + * is delayed for any reason (such as garbage collection or other
1.222 + * background activity), subsequent executions will be delayed as well.
1.223 + * In the long run, the frequency of execution will generally be slightly
1.224 + * lower than the reciprocal of the specified period (assuming the system
1.225 + * clock underlying <tt>Object.wait(long)</tt> is accurate).
1.226 + *
1.227 + * <p>Fixed-delay execution is appropriate for recurring activities
1.228 + * that require "smoothness." In other words, it is appropriate for
1.229 + * activities where it is more important to keep the frequency accurate
1.230 + * in the short run than in the long run. This includes most animation
1.231 + * tasks, such as blinking a cursor at regular intervals. It also includes
1.232 + * tasks wherein regular activity is performed in response to human
1.233 + * input, such as automatically repeating a character as long as a key
1.234 + * is held down.
1.235 + *
1.236 + * @param task task to be scheduled.
1.237 + * @param delay delay in milliseconds before task is to be executed.
1.238 + * @param period time in milliseconds between successive task executions.
1.239 + * @throws IllegalArgumentException if {@code delay < 0}, or
1.240 + * {@code delay + System.currentTimeMillis() < 0}, or
1.241 + * {@code period <= 0}
1.242 + * @throws IllegalStateException if task was already scheduled or
1.243 + * cancelled, timer was cancelled, or timer thread terminated.
1.244 + * @throws NullPointerException if {@code task} is null
1.245 + */
1.246 + public void schedule(TimerTask task, long delay, long period) {
1.247 + if (delay < 0)
1.248 + throw new IllegalArgumentException("Negative delay.");
1.249 + if (period <= 0)
1.250 + throw new IllegalArgumentException("Non-positive period.");
1.251 + sched(task, System.currentTimeMillis()+delay, -period);
1.252 + }
1.253 +
1.254 + /**
1.255 + * Schedules the specified task for repeated <i>fixed-delay execution</i>,
1.256 + * beginning at the specified time. Subsequent executions take place at
1.257 + * approximately regular intervals, separated by the specified period.
1.258 + *
1.259 + * <p>In fixed-delay execution, each execution is scheduled relative to
1.260 + * the actual execution time of the previous execution. If an execution
1.261 + * is delayed for any reason (such as garbage collection or other
1.262 + * background activity), subsequent executions will be delayed as well.
1.263 + * In the long run, the frequency of execution will generally be slightly
1.264 + * lower than the reciprocal of the specified period (assuming the system
1.265 + * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
1.266 + * consequence of the above, if the scheduled first time is in the past,
1.267 + * it is scheduled for immediate execution.
1.268 + *
1.269 + * <p>Fixed-delay execution is appropriate for recurring activities
1.270 + * that require "smoothness." In other words, it is appropriate for
1.271 + * activities where it is more important to keep the frequency accurate
1.272 + * in the short run than in the long run. This includes most animation
1.273 + * tasks, such as blinking a cursor at regular intervals. It also includes
1.274 + * tasks wherein regular activity is performed in response to human
1.275 + * input, such as automatically repeating a character as long as a key
1.276 + * is held down.
1.277 + *
1.278 + * @param task task to be scheduled.
1.279 + * @param firstTime First time at which task is to be executed.
1.280 + * @param period time in milliseconds between successive task executions.
1.281 + * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
1.282 + * {@code period <= 0}
1.283 + * @throws IllegalStateException if task was already scheduled or
1.284 + * cancelled, timer was cancelled, or timer thread terminated.
1.285 + * @throws NullPointerException if {@code task} or {@code firstTime} is null
1.286 + */
1.287 + public void schedule(TimerTask task, Date firstTime, long period) {
1.288 + if (period <= 0)
1.289 + throw new IllegalArgumentException("Non-positive period.");
1.290 + sched(task, firstTime.getTime(), -period);
1.291 + }
1.292 +
1.293 + /**
1.294 + * Schedules the specified task for repeated <i>fixed-rate execution</i>,
1.295 + * beginning after the specified delay. Subsequent executions take place
1.296 + * at approximately regular intervals, separated by the specified period.
1.297 + *
1.298 + * <p>In fixed-rate execution, each execution is scheduled relative to the
1.299 + * scheduled execution time of the initial execution. If an execution is
1.300 + * delayed for any reason (such as garbage collection or other background
1.301 + * activity), two or more executions will occur in rapid succession to
1.302 + * "catch up." In the long run, the frequency of execution will be
1.303 + * exactly the reciprocal of the specified period (assuming the system
1.304 + * clock underlying <tt>Object.wait(long)</tt> is accurate).
1.305 + *
1.306 + * <p>Fixed-rate execution is appropriate for recurring activities that
1.307 + * are sensitive to <i>absolute</i> time, such as ringing a chime every
1.308 + * hour on the hour, or running scheduled maintenance every day at a
1.309 + * particular time. It is also appropriate for recurring activities
1.310 + * where the total time to perform a fixed number of executions is
1.311 + * important, such as a countdown timer that ticks once every second for
1.312 + * ten seconds. Finally, fixed-rate execution is appropriate for
1.313 + * scheduling multiple repeating timer tasks that must remain synchronized
1.314 + * with respect to one another.
1.315 + *
1.316 + * @param task task to be scheduled.
1.317 + * @param delay delay in milliseconds before task is to be executed.
1.318 + * @param period time in milliseconds between successive task executions.
1.319 + * @throws IllegalArgumentException if {@code delay < 0}, or
1.320 + * {@code delay + System.currentTimeMillis() < 0}, or
1.321 + * {@code period <= 0}
1.322 + * @throws IllegalStateException if task was already scheduled or
1.323 + * cancelled, timer was cancelled, or timer thread terminated.
1.324 + * @throws NullPointerException if {@code task} is null
1.325 + */
1.326 + public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
1.327 + if (delay < 0)
1.328 + throw new IllegalArgumentException("Negative delay.");
1.329 + if (period <= 0)
1.330 + throw new IllegalArgumentException("Non-positive period.");
1.331 + sched(task, System.currentTimeMillis()+delay, period);
1.332 + }
1.333 +
1.334 + /**
1.335 + * Schedules the specified task for repeated <i>fixed-rate execution</i>,
1.336 + * beginning at the specified time. Subsequent executions take place at
1.337 + * approximately regular intervals, separated by the specified period.
1.338 + *
1.339 + * <p>In fixed-rate execution, each execution is scheduled relative to the
1.340 + * scheduled execution time of the initial execution. If an execution is
1.341 + * delayed for any reason (such as garbage collection or other background
1.342 + * activity), two or more executions will occur in rapid succession to
1.343 + * "catch up." In the long run, the frequency of execution will be
1.344 + * exactly the reciprocal of the specified period (assuming the system
1.345 + * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
1.346 + * consequence of the above, if the scheduled first time is in the past,
1.347 + * then any "missed" executions will be scheduled for immediate "catch up"
1.348 + * execution.
1.349 + *
1.350 + * <p>Fixed-rate execution is appropriate for recurring activities that
1.351 + * are sensitive to <i>absolute</i> time, such as ringing a chime every
1.352 + * hour on the hour, or running scheduled maintenance every day at a
1.353 + * particular time. It is also appropriate for recurring activities
1.354 + * where the total time to perform a fixed number of executions is
1.355 + * important, such as a countdown timer that ticks once every second for
1.356 + * ten seconds. Finally, fixed-rate execution is appropriate for
1.357 + * scheduling multiple repeating timer tasks that must remain synchronized
1.358 + * with respect to one another.
1.359 + *
1.360 + * @param task task to be scheduled.
1.361 + * @param firstTime First time at which task is to be executed.
1.362 + * @param period time in milliseconds between successive task executions.
1.363 + * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
1.364 + * {@code period <= 0}
1.365 + * @throws IllegalStateException if task was already scheduled or
1.366 + * cancelled, timer was cancelled, or timer thread terminated.
1.367 + * @throws NullPointerException if {@code task} or {@code firstTime} is null
1.368 + */
1.369 + public void scheduleAtFixedRate(TimerTask task, Date firstTime,
1.370 + long period) {
1.371 + if (period <= 0)
1.372 + throw new IllegalArgumentException("Non-positive period.");
1.373 + sched(task, firstTime.getTime(), period);
1.374 + }
1.375 +
1.376 + /**
1.377 + * Schedule the specified timer task for execution at the specified
1.378 + * time with the specified period, in milliseconds. If period is
1.379 + * positive, the task is scheduled for repeated execution; if period is
1.380 + * zero, the task is scheduled for one-time execution. Time is specified
1.381 + * in Date.getTime() format. This method checks timer state, task state,
1.382 + * and initial execution time, but not period.
1.383 + *
1.384 + * @throws IllegalArgumentException if <tt>time</tt> is negative.
1.385 + * @throws IllegalStateException if task was already scheduled or
1.386 + * cancelled, timer was cancelled, or timer thread terminated.
1.387 + * @throws NullPointerException if {@code task} is null
1.388 + */
1.389 + private void sched(TimerTask task, long time, long period) {
1.390 + if (time < 0)
1.391 + throw new IllegalArgumentException("Illegal execution time.");
1.392 +
1.393 + // Constrain value of period sufficiently to prevent numeric
1.394 + // overflow while still being effectively infinitely large.
1.395 + if (Math.abs(period) > (Long.MAX_VALUE >> 1))
1.396 + period >>= 1;
1.397 +
1.398 + synchronized(queue) {
1.399 + if (!thread.newTasksMayBeScheduled)
1.400 + throw new IllegalStateException("Timer already cancelled.");
1.401 +
1.402 + synchronized(task.lock) {
1.403 + if (task.state != TimerTask.VIRGIN)
1.404 + throw new IllegalStateException(
1.405 + "Task already scheduled or cancelled");
1.406 + task.nextExecutionTime = time;
1.407 + task.period = period;
1.408 + task.state = TimerTask.SCHEDULED;
1.409 + }
1.410 +
1.411 + queue.add(task);
1.412 + if (queue.getMin() == task)
1.413 + queue.notify();
1.414 + }
1.415 + }
1.416 +
1.417 + /**
1.418 + * Terminates this timer, discarding any currently scheduled tasks.
1.419 + * Does not interfere with a currently executing task (if it exists).
1.420 + * Once a timer has been terminated, its execution thread terminates
1.421 + * gracefully, and no more tasks may be scheduled on it.
1.422 + *
1.423 + * <p>Note that calling this method from within the run method of a
1.424 + * timer task that was invoked by this timer absolutely guarantees that
1.425 + * the ongoing task execution is the last task execution that will ever
1.426 + * be performed by this timer.
1.427 + *
1.428 + * <p>This method may be called repeatedly; the second and subsequent
1.429 + * calls have no effect.
1.430 + */
1.431 + public void cancel() {
1.432 + synchronized(queue) {
1.433 + thread.newTasksMayBeScheduled = false;
1.434 + queue.clear();
1.435 + queue.notify(); // In case queue was already empty.
1.436 + }
1.437 + }
1.438 +
1.439 + /**
1.440 + * Removes all cancelled tasks from this timer's task queue. <i>Calling
1.441 + * this method has no effect on the behavior of the timer</i>, but
1.442 + * eliminates the references to the cancelled tasks from the queue.
1.443 + * If there are no external references to these tasks, they become
1.444 + * eligible for garbage collection.
1.445 + *
1.446 + * <p>Most programs will have no need to call this method.
1.447 + * It is designed for use by the rare application that cancels a large
1.448 + * number of tasks. Calling this method trades time for space: the
1.449 + * runtime of the method may be proportional to n + c log n, where n
1.450 + * is the number of tasks in the queue and c is the number of cancelled
1.451 + * tasks.
1.452 + *
1.453 + * <p>Note that it is permissible to call this method from within a
1.454 + * a task scheduled on this timer.
1.455 + *
1.456 + * @return the number of tasks removed from the queue.
1.457 + * @since 1.5
1.458 + */
1.459 + public int purge() {
1.460 + int result = 0;
1.461 +
1.462 + synchronized(queue) {
1.463 + for (int i = queue.size(); i > 0; i--) {
1.464 + if (queue.get(i).state == TimerTask.CANCELLED) {
1.465 + queue.quickRemove(i);
1.466 + result++;
1.467 + }
1.468 + }
1.469 +
1.470 + if (result != 0)
1.471 + queue.heapify();
1.472 + }
1.473 +
1.474 + return result;
1.475 + }
1.476 +}
1.477 +
1.478 +/**
1.479 + * This "helper class" implements the timer's task execution thread, which
1.480 + * waits for tasks on the timer queue, executions them when they fire,
1.481 + * reschedules repeating tasks, and removes cancelled tasks and spent
1.482 + * non-repeating tasks from the queue.
1.483 + */
1.484 +class TimerThread extends Thread {
1.485 + /**
1.486 + * This flag is set to false by the reaper to inform us that there
1.487 + * are no more live references to our Timer object. Once this flag
1.488 + * is true and there are no more tasks in our queue, there is no
1.489 + * work left for us to do, so we terminate gracefully. Note that
1.490 + * this field is protected by queue's monitor!
1.491 + */
1.492 + boolean newTasksMayBeScheduled = true;
1.493 +
1.494 + /**
1.495 + * Our Timer's queue. We store this reference in preference to
1.496 + * a reference to the Timer so the reference graph remains acyclic.
1.497 + * Otherwise, the Timer would never be garbage-collected and this
1.498 + * thread would never go away.
1.499 + */
1.500 + private TaskQueue queue;
1.501 +
1.502 + TimerThread(TaskQueue queue) {
1.503 + this.queue = queue;
1.504 + }
1.505 +
1.506 + public void run() {
1.507 + try {
1.508 + mainLoop();
1.509 + } finally {
1.510 + // Someone killed this Thread, behave as if Timer cancelled
1.511 + synchronized(queue) {
1.512 + newTasksMayBeScheduled = false;
1.513 + queue.clear(); // Eliminate obsolete references
1.514 + }
1.515 + }
1.516 + }
1.517 +
1.518 + /**
1.519 + * The main timer loop. (See class comment.)
1.520 + */
1.521 + private void mainLoop() {
1.522 + while (true) {
1.523 + try {
1.524 + TimerTask task;
1.525 + boolean taskFired;
1.526 + synchronized(queue) {
1.527 + // Wait for queue to become non-empty
1.528 + while (queue.isEmpty() && newTasksMayBeScheduled)
1.529 + queue.wait();
1.530 + if (queue.isEmpty())
1.531 + break; // Queue is empty and will forever remain; die
1.532 +
1.533 + // Queue nonempty; look at first evt and do the right thing
1.534 + long currentTime, executionTime;
1.535 + task = queue.getMin();
1.536 + synchronized(task.lock) {
1.537 + if (task.state == TimerTask.CANCELLED) {
1.538 + queue.removeMin();
1.539 + continue; // No action required, poll queue again
1.540 + }
1.541 + currentTime = System.currentTimeMillis();
1.542 + executionTime = task.nextExecutionTime;
1.543 + if (taskFired = (executionTime<=currentTime)) {
1.544 + if (task.period == 0) { // Non-repeating, remove
1.545 + queue.removeMin();
1.546 + task.state = TimerTask.EXECUTED;
1.547 + } else { // Repeating task, reschedule
1.548 + queue.rescheduleMin(
1.549 + task.period<0 ? currentTime - task.period
1.550 + : executionTime + task.period);
1.551 + }
1.552 + }
1.553 + }
1.554 + if (!taskFired) // Task hasn't yet fired; wait
1.555 + queue.wait(executionTime - currentTime);
1.556 + }
1.557 + if (taskFired) // Task fired; run it, holding no locks
1.558 + task.run();
1.559 + } catch(InterruptedException e) {
1.560 + }
1.561 + }
1.562 + }
1.563 +}
1.564 +
1.565 +/**
1.566 + * This class represents a timer task queue: a priority queue of TimerTasks,
1.567 + * ordered on nextExecutionTime. Each Timer object has one of these, which it
1.568 + * shares with its TimerThread. Internally this class uses a heap, which
1.569 + * offers log(n) performance for the add, removeMin and rescheduleMin
1.570 + * operations, and constant time performance for the getMin operation.
1.571 + */
1.572 +class TaskQueue {
1.573 + /**
1.574 + * Priority queue represented as a balanced binary heap: the two children
1.575 + * of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is
1.576 + * ordered on the nextExecutionTime field: The TimerTask with the lowest
1.577 + * nextExecutionTime is in queue[1] (assuming the queue is nonempty). For
1.578 + * each node n in the heap, and each descendant of n, d,
1.579 + * n.nextExecutionTime <= d.nextExecutionTime.
1.580 + */
1.581 + private TimerTask[] queue = new TimerTask[128];
1.582 +
1.583 + /**
1.584 + * The number of tasks in the priority queue. (The tasks are stored in
1.585 + * queue[1] up to queue[size]).
1.586 + */
1.587 + private int size = 0;
1.588 +
1.589 + /**
1.590 + * Returns the number of tasks currently on the queue.
1.591 + */
1.592 + int size() {
1.593 + return size;
1.594 + }
1.595 +
1.596 + /**
1.597 + * Adds a new task to the priority queue.
1.598 + */
1.599 + void add(TimerTask task) {
1.600 + // Grow backing store if necessary
1.601 + if (size + 1 == queue.length)
1.602 + queue = Arrays.copyOf(queue, 2*queue.length);
1.603 +
1.604 + queue[++size] = task;
1.605 + fixUp(size);
1.606 + }
1.607 +
1.608 + /**
1.609 + * Return the "head task" of the priority queue. (The head task is an
1.610 + * task with the lowest nextExecutionTime.)
1.611 + */
1.612 + TimerTask getMin() {
1.613 + return queue[1];
1.614 + }
1.615 +
1.616 + /**
1.617 + * Return the ith task in the priority queue, where i ranges from 1 (the
1.618 + * head task, which is returned by getMin) to the number of tasks on the
1.619 + * queue, inclusive.
1.620 + */
1.621 + TimerTask get(int i) {
1.622 + return queue[i];
1.623 + }
1.624 +
1.625 + /**
1.626 + * Remove the head task from the priority queue.
1.627 + */
1.628 + void removeMin() {
1.629 + queue[1] = queue[size];
1.630 + queue[size--] = null; // Drop extra reference to prevent memory leak
1.631 + fixDown(1);
1.632 + }
1.633 +
1.634 + /**
1.635 + * Removes the ith element from queue without regard for maintaining
1.636 + * the heap invariant. Recall that queue is one-based, so
1.637 + * 1 <= i <= size.
1.638 + */
1.639 + void quickRemove(int i) {
1.640 + assert i <= size;
1.641 +
1.642 + queue[i] = queue[size];
1.643 + queue[size--] = null; // Drop extra ref to prevent memory leak
1.644 + }
1.645 +
1.646 + /**
1.647 + * Sets the nextExecutionTime associated with the head task to the
1.648 + * specified value, and adjusts priority queue accordingly.
1.649 + */
1.650 + void rescheduleMin(long newTime) {
1.651 + queue[1].nextExecutionTime = newTime;
1.652 + fixDown(1);
1.653 + }
1.654 +
1.655 + /**
1.656 + * Returns true if the priority queue contains no elements.
1.657 + */
1.658 + boolean isEmpty() {
1.659 + return size==0;
1.660 + }
1.661 +
1.662 + /**
1.663 + * Removes all elements from the priority queue.
1.664 + */
1.665 + void clear() {
1.666 + // Null out task references to prevent memory leak
1.667 + for (int i=1; i<=size; i++)
1.668 + queue[i] = null;
1.669 +
1.670 + size = 0;
1.671 + }
1.672 +
1.673 + /**
1.674 + * Establishes the heap invariant (described above) assuming the heap
1.675 + * satisfies the invariant except possibly for the leaf-node indexed by k
1.676 + * (which may have a nextExecutionTime less than its parent's).
1.677 + *
1.678 + * This method functions by "promoting" queue[k] up the hierarchy
1.679 + * (by swapping it with its parent) repeatedly until queue[k]'s
1.680 + * nextExecutionTime is greater than or equal to that of its parent.
1.681 + */
1.682 + private void fixUp(int k) {
1.683 + while (k > 1) {
1.684 + int j = k >> 1;
1.685 + if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
1.686 + break;
1.687 + TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
1.688 + k = j;
1.689 + }
1.690 + }
1.691 +
1.692 + /**
1.693 + * Establishes the heap invariant (described above) in the subtree
1.694 + * rooted at k, which is assumed to satisfy the heap invariant except
1.695 + * possibly for node k itself (which may have a nextExecutionTime greater
1.696 + * than its children's).
1.697 + *
1.698 + * This method functions by "demoting" queue[k] down the hierarchy
1.699 + * (by swapping it with its smaller child) repeatedly until queue[k]'s
1.700 + * nextExecutionTime is less than or equal to those of its children.
1.701 + */
1.702 + private void fixDown(int k) {
1.703 + int j;
1.704 + while ((j = k << 1) <= size && j > 0) {
1.705 + if (j < size &&
1.706 + queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
1.707 + j++; // j indexes smallest kid
1.708 + if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
1.709 + break;
1.710 + TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
1.711 + k = j;
1.712 + }
1.713 + }
1.714 +
1.715 + /**
1.716 + * Establishes the heap invariant (described above) in the entire tree,
1.717 + * assuming nothing about the order of the elements prior to the call.
1.718 + */
1.719 + void heapify() {
1.720 + for (int i = size/2; i >= 1; i--)
1.721 + fixDown(i);
1.722 + }
1.723 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/rt/emul/compact/src/main/java/java/util/TimerTask.java Sat Nov 02 16:43:48 2013 +0100
2.3 @@ -0,0 +1,158 @@
2.4 +/*
2.5 + * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2.7 + *
2.8 + * This code is free software; you can redistribute it and/or modify it
2.9 + * under the terms of the GNU General Public License version 2 only, as
2.10 + * published by the Free Software Foundation. Oracle designates this
2.11 + * particular file as subject to the "Classpath" exception as provided
2.12 + * by Oracle in the LICENSE file that accompanied this code.
2.13 + *
2.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
2.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2.17 + * version 2 for more details (a copy is included in the LICENSE file that
2.18 + * accompanied this code).
2.19 + *
2.20 + * You should have received a copy of the GNU General Public License version
2.21 + * 2 along with this work; if not, write to the Free Software Foundation,
2.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2.23 + *
2.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2.25 + * or visit www.oracle.com if you need additional information or have any
2.26 + * questions.
2.27 + */
2.28 +
2.29 +package java.util;
2.30 +
2.31 +/**
2.32 + * A task that can be scheduled for one-time or repeated execution by a Timer.
2.33 + *
2.34 + * @author Josh Bloch
2.35 + * @see Timer
2.36 + * @since 1.3
2.37 + */
2.38 +
2.39 +public abstract class TimerTask implements Runnable {
2.40 + /**
2.41 + * This object is used to control access to the TimerTask internals.
2.42 + */
2.43 + final Object lock = new Object();
2.44 +
2.45 + /**
2.46 + * The state of this task, chosen from the constants below.
2.47 + */
2.48 + int state = VIRGIN;
2.49 +
2.50 + /**
2.51 + * This task has not yet been scheduled.
2.52 + */
2.53 + static final int VIRGIN = 0;
2.54 +
2.55 + /**
2.56 + * This task is scheduled for execution. If it is a non-repeating task,
2.57 + * it has not yet been executed.
2.58 + */
2.59 + static final int SCHEDULED = 1;
2.60 +
2.61 + /**
2.62 + * This non-repeating task has already executed (or is currently
2.63 + * executing) and has not been cancelled.
2.64 + */
2.65 + static final int EXECUTED = 2;
2.66 +
2.67 + /**
2.68 + * This task has been cancelled (with a call to TimerTask.cancel).
2.69 + */
2.70 + static final int CANCELLED = 3;
2.71 +
2.72 + /**
2.73 + * Next execution time for this task in the format returned by
2.74 + * System.currentTimeMillis, assuming this task is scheduled for execution.
2.75 + * For repeating tasks, this field is updated prior to each task execution.
2.76 + */
2.77 + long nextExecutionTime;
2.78 +
2.79 + /**
2.80 + * Period in milliseconds for repeating tasks. A positive value indicates
2.81 + * fixed-rate execution. A negative value indicates fixed-delay execution.
2.82 + * A value of 0 indicates a non-repeating task.
2.83 + */
2.84 + long period = 0;
2.85 +
2.86 + /**
2.87 + * Creates a new timer task.
2.88 + */
2.89 + protected TimerTask() {
2.90 + }
2.91 +
2.92 + /**
2.93 + * The action to be performed by this timer task.
2.94 + */
2.95 + public abstract void run();
2.96 +
2.97 + /**
2.98 + * Cancels this timer task. If the task has been scheduled for one-time
2.99 + * execution and has not yet run, or has not yet been scheduled, it will
2.100 + * never run. If the task has been scheduled for repeated execution, it
2.101 + * will never run again. (If the task is running when this call occurs,
2.102 + * the task will run to completion, but will never run again.)
2.103 + *
2.104 + * <p>Note that calling this method from within the <tt>run</tt> method of
2.105 + * a repeating timer task absolutely guarantees that the timer task will
2.106 + * not run again.
2.107 + *
2.108 + * <p>This method may be called repeatedly; the second and subsequent
2.109 + * calls have no effect.
2.110 + *
2.111 + * @return true if this task is scheduled for one-time execution and has
2.112 + * not yet run, or this task is scheduled for repeated execution.
2.113 + * Returns false if the task was scheduled for one-time execution
2.114 + * and has already run, or if the task was never scheduled, or if
2.115 + * the task was already cancelled. (Loosely speaking, this method
2.116 + * returns <tt>true</tt> if it prevents one or more scheduled
2.117 + * executions from taking place.)
2.118 + */
2.119 + public boolean cancel() {
2.120 + synchronized(lock) {
2.121 + boolean result = (state == SCHEDULED);
2.122 + state = CANCELLED;
2.123 + return result;
2.124 + }
2.125 + }
2.126 +
2.127 + /**
2.128 + * Returns the <i>scheduled</i> execution time of the most recent
2.129 + * <i>actual</i> execution of this task. (If this method is invoked
2.130 + * while task execution is in progress, the return value is the scheduled
2.131 + * execution time of the ongoing task execution.)
2.132 + *
2.133 + * <p>This method is typically invoked from within a task's run method, to
2.134 + * determine whether the current execution of the task is sufficiently
2.135 + * timely to warrant performing the scheduled activity:
2.136 + * <pre>
2.137 + * public void run() {
2.138 + * if (System.currentTimeMillis() - scheduledExecutionTime() >=
2.139 + * MAX_TARDINESS)
2.140 + * return; // Too late; skip this execution.
2.141 + * // Perform the task
2.142 + * }
2.143 + * </pre>
2.144 + * This method is typically <i>not</i> used in conjunction with
2.145 + * <i>fixed-delay execution</i> repeating tasks, as their scheduled
2.146 + * execution times are allowed to drift over time, and so are not terribly
2.147 + * significant.
2.148 + *
2.149 + * @return the time at which the most recent execution of this task was
2.150 + * scheduled to occur, in the format returned by Date.getTime().
2.151 + * The return value is undefined if the task has yet to commence
2.152 + * its first execution.
2.153 + * @see Date#getTime()
2.154 + */
2.155 + public long scheduledExecutionTime() {
2.156 + synchronized(lock) {
2.157 + return (period < 0 ? nextExecutionTime + period
2.158 + : nextExecutionTime - period);
2.159 + }
2.160 + }
2.161 +}