/*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A facility for threads to schedule tasks for future execution in a
* background thread. Tasks may be scheduled for one-time execution, or for
* repeated execution at regular intervals.
*
* <p>Corresponding to each <tt>Timer</tt> object is a single background
* thread that is used to execute all of the timer's tasks, sequentially.
* Timer tasks should complete quickly. If a timer task takes excessive time
* to complete, it "hogs" the timer's task execution thread. This can, in
* turn, delay the execution of subsequent tasks, which may "bunch up" and
* execute in rapid succession when (and if) the offending task finally
* completes.
*
* <p>After the last live reference to a <tt>Timer</tt> object goes away
* <i>and</i> all outstanding tasks have completed execution, the timer's task
* execution thread terminates gracefully (and becomes subject to garbage
* collection). However, this can take arbitrarily long to occur. By
* default, the task execution thread does not run as a <i>daemon thread</i>,
* so it is capable of keeping an application from terminating. If a caller
* wants to terminate a timer's task execution thread rapidly, the caller
* should invoke the timer's <tt>cancel</tt> method.
*
* <p>If the timer's task execution thread terminates unexpectedly, for
* example, because its <tt>stop</tt> method is invoked, any further
* attempt to schedule a task on the timer will result in an
* <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
* method had been invoked.
*
* <p>This class is thread-safe: multiple threads can share a single
* <tt>Timer</tt> object without the need for external synchronization.
*
* <p>This class does <i>not</i> offer real-time guarantees: it schedules
* tasks using the <tt>Object.wait(long)</tt> method.
*
* <p>Java 5.0 introduced the {@code java.util.concurrent} package and
* one of the concurrency utilities therein is the {@link
* java.util.concurrent.ScheduledThreadPoolExecutor
* ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
* executing tasks at a given rate or delay. It is effectively a more
* versatile replacement for the {@code Timer}/{@code TimerTask}
* combination, as it allows multiple service threads, accepts various
* time units, and doesn't require subclassing {@code TimerTask} (just
* implement {@code Runnable}). Configuring {@code
* ScheduledThreadPoolExecutor} with one thread makes it equivalent to
* {@code Timer}.
*
* <p>Implementation note: This class scales to large numbers of concurrently
* scheduled tasks (thousands should present no problem). Internally,
* it uses a binary heap to represent its task queue, so the cost to schedule
* a task is O(log n), where n is the number of concurrently scheduled tasks.
*
* <p>Implementation note: All constructors start a timer thread.
*
* @author Josh Bloch
* @see TimerTask
* @see Object#wait(long)
* @since 1.3
*/
public class Timer {
/**
* The timer task queue. This data structure is shared with the timer
* thread. The timer produces tasks, via its various schedule calls,
* and the timer thread consumes, executing timer tasks as appropriate,
* and removing them from the queue when they're obsolete.
*/
private final TaskQueue queue = new TaskQueue();
/**
* The timer thread.
*/
private final TimerThread thread = new TimerThread(queue);
/**
* This object causes the timer's task execution thread to exit
* gracefully when there are no live references to the Timer object and no
* tasks in the timer queue. It is used in preference to a finalizer on
* Timer as such a finalizer would be susceptible to a subclass's
* finalizer forgetting to call it.
*/
private final Object threadReaper = new Object() {
protected void finalize() throws Throwable {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.notify(); // In case queue is empty.
}
}
};
/**
* This ID is used to generate thread names.
*/
private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
private static int serialNumber() {
return nextSerialNumber.getAndIncrement();
}
/**
* Creates a new timer. The associated thread does <i>not</i>
* {@linkplain Thread#setDaemon run as a daemon}.
*/
public Timer() {
this("Timer-" + serialNumber());
}
/**
* Creates a new timer whose associated thread may be specified to
* {@linkplain Thread#setDaemon run as a daemon}.
* A daemon thread is called for if the timer will be used to
* schedule repeating "maintenance activities", which must be
* performed as long as the application is running, but should not
* prolong the lifetime of the application.
*
* @param isDaemon true if the associated thread should run as a daemon.
*/
public Timer(boolean isDaemon) {
this("Timer-" + serialNumber(), isDaemon);
}
/**
* Creates a new timer whose associated thread has the specified name.
* The associated thread does <i>not</i>
* {@linkplain Thread#setDaemon run as a daemon}.
*
* @param name the name of the associated thread
* @throws NullPointerException if {@code name} is null
* @since 1.5
*/
public Timer(String name) {
thread.setName(name);
thread.start();
}
/**
* Creates a new timer whose associated thread has the specified name,
* and may be specified to
* {@linkplain Thread#setDaemon run as a daemon}.
*
* @param name the name of the associated thread
* @param isDaemon true if the associated thread should run as a daemon
* @throws NullPointerException if {@code name} is null
* @since 1.5
*/
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();
}
/**
* Schedules the specified task for execution after the specified delay.
*
* @param task task to be scheduled.
* @param delay delay in milliseconds before task is to be executed.
* @throws IllegalArgumentException if <tt>delay</tt> is negative, or
* <tt>delay + System.currentTimeMillis()</tt> is negative.
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} is null
*/
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
/**
* Schedules the specified task for execution at the specified time. If
* the time is in the past, the task is scheduled for immediate execution.
*
* @param task task to be scheduled.
* @param time time at which task is to be executed.
* @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} or {@code time} is null
*/
public void schedule(TimerTask task, Date time) {
sched(task, time.getTime(), 0);
}
/**
* Schedules the specified task for repeated <i>fixed-delay execution</i>,
* beginning after the specified delay. Subsequent executions take place