--- a/jdk/src/share/classes/sun/misc/Timer.java Thu Jun 19 11:22:18 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,647 +0,0 @@
-/*
- * Copyright (c) 1995, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/**
- A Timer object is used by algorithms that require timed events.
- For example, in an animation loop, a timer would help in
- determining when to change frames.
-
- A timer has an interval which determines when it "ticks";
- that is, a timer delays for the specified interval and then
- it calls the owner's tick() method.
-
- Here's an example of creating a timer with a 5 sec interval:
-
- <pre>
- class Main implements Timeable {
- public void tick(Timer timer) {
- System.out.println("tick");
- }
- public static void main(String args[]) {
- (new Timer(this, 5000)).cont();
- }
- }
- </pre>
-
- A timer can be stopped, continued, or reset at any time.
- A timer's state is not stopped while it's calling the
- owner's tick() method.
-
- A timer can be regular or irregular. If in regular mode,
- a timer ticks at the specified interval, regardless of
- how long the owner's tick() method takes. While the timer
- is running, no ticks are ever discarded. That means that if
- the owner's tick() method takes longer than the interval,
- the ticks that would have occurred are delivered immediately.
-
- In irregular mode, a timer starts delaying for exactly
- the specified interval only after the tick() method returns.
-
- Synchronization issues: do not hold the timer's monitor
- while calling any of the Timer operations below otherwise
- the Timer class will deadlock.
-
- @author Patrick Chan
-*/
-
-/*
- Synchronization issues: there are two data structures that
- require locking. A Timer object and the Timer queue
- (described in the TimerThread class). To avoid deadlock,
- the timer queue monitor is always acquired before the timer
- object's monitor. However, the timer queue monitor is acquired
- only if the timer operation will make use of the timer
- queue, e.g. stop().
-
- The class monitor on the class TimerThread severs as the monitor
- to the timer queue.
-
- Possible feature: perhaps a timer should have an associated
- thread priority. The thread that makes the callback temporarily
- takes on that priority before calling the owner's tick() method.
-*/
-
-public class Timer {
- /**
- * This is the owner of the timer. Its tick method is
- * called when the timer ticks.
- */
- public Timeable owner;
-
- /*
- * This is the interval of time in ms.
- */
- long interval;
-
- /*
- * This variable is used for two different purposes.
- * This is done in order to save space.
- * If 'stopped' is true, this variable holds the time
- * that the timer was stopped; otherwise, this variable
- * is used by the TimerThread to determine when the timer
- * should tick.
- */
- long sleepUntil;
-
- /*
- * This is the time remaining before the timer ticks. It
- * is only valid if 'stopped' is true. If the timer is
- * continued, the next tick will happen remaingTime
- * milliseconds later.
- */
- long remainingTime;
-
- /*
- * True iff the timer is in regular mode.
- */
- boolean regular;
-
- /*
- * True iff the timer has been stopped.
- */
- boolean stopped;
-
- /* **************************************************************
- * Timer queue-related variables
- * ************************************************************** */
-
- /*
- * A link to another timer object. This is used while the
- * timer object is enqueued in the timer queue.
- */
- Timer next;
-
- /* **************************************************************
- * Timer methods
- * ************************************************************** */
-
- /*
- * This variable holds a handle to the TimerThread class for
- * the purpose of getting at the class monitor. The reason
- * why Class.forName("TimerThread") is not used is because it
- * doesn't appear to work when loaded via a net class loader.
- */
- static TimerThread timerThread = null;
-
- /**
- * Creates a timer object that is owned by 'owner' and
- * with the interval 'interval' milliseconds. The new timer
- * object is stopped and is regular. getRemainingTime()
- * return 'interval' at this point. getStopTime() returns
- * the time this object was created.
- * @param owner owner of the timer object
- * @param interval interval of the timer in milliseconds
- */
- public Timer(Timeable owner, long interval) {
- this.owner = owner;
- this.interval = interval;
- remainingTime = interval;
- regular = true;
- sleepUntil = System.currentTimeMillis();
- stopped = true;
- synchronized (getClass()) {
- if (timerThread == null) {
- timerThread = new TimerThread();
- }
- }
- }
-
- /**
- * Returns true if this timer is stopped.
- */
- public synchronized boolean isStopped() {
- return stopped;
- }
-
- /**
- * Stops the timer. The amount of time the timer has already
- * delayed is saved so if the timer is continued, it will only
- * delay for the amount of time remaining.
- * Note that even after stopping a timer, one more tick may
- * still occur.
- * This method is MT-safe; i.e. it is synchronized but for
- * implementation reasons, the synchronized modifier cannot
- * be included in the method declaration.
- */
- public void stop() {
- long now = System.currentTimeMillis();
-
- synchronized (timerThread) {
- synchronized (this) {
- if (!stopped) {
- TimerThread.dequeue(this);
- remainingTime = Math.max(0, sleepUntil - now);
- sleepUntil = now; // stop time
- stopped = true;
- }
- }
- }
- }
-
- /**
- * Continue the timer. The next tick will come at getRemainingTime()
- * milliseconds later. If the timer is not stopped, this
- * call will be a no-op.
- * This method is MT-safe; i.e. it is synchronized but for
- * implementation reasons, the synchronized modifier cannot
- * be included in the method declaration.
- */
- public void cont() {
- synchronized (timerThread) {
- synchronized (this) {
- if (stopped) {
- // The TimerTickThread avoids requeuing the
- // timer only if the sleepUntil value has changed.
- // The following guarantees that the sleepUntil
- // value will be different; without this guarantee,
- // it's theoretically possible for the timer to be
- // inserted twice.
- sleepUntil = Math.max(sleepUntil + 1,
- System.currentTimeMillis() + remainingTime);
- TimerThread.enqueue(this);
- stopped = false;
- }
- }
- }
- }
-
- /**
- * Resets the timer's remaining time to the timer's interval.
- * If the timer's running state is not altered.
- */
- public void reset() {
- synchronized (timerThread) {
- synchronized (this) {
- setRemainingTime(interval);
- }
- }
- }
-
- /**
- * Returns the time at which the timer was last stopped. The
- * return value is valid only if the timer is stopped.
- */
- public synchronized long getStopTime() {
- return sleepUntil;
- }
-
- /**
- * Returns the timer's interval.
- */
- public synchronized long getInterval() {
- return interval;
- }
-
- /**
- * Changes the timer's interval. The new interval setting
- * does not take effect until after the next tick.
- * This method does not alter the remaining time or the
- * running state of the timer.
- * @param interval new interval of the timer in milliseconds
- */
- public synchronized void setInterval(long interval) {
- this.interval = interval;
- }
-
- /**
- * Returns the remaining time before the timer's next tick.
- * The return value is valid only if timer is stopped.
- */
- public synchronized long getRemainingTime() {
- return remainingTime;
- }
-
- /**
- * Sets the remaining time before the timer's next tick.
- * This method does not alter the timer's running state.
- * This method is MT-safe; i.e. it is synchronized but for
- * implementation reasons, the synchronized modifier cannot
- * be included in the method declaration.
- * @param time new remaining time in milliseconds.
- */
- public void setRemainingTime(long time) {
- synchronized (timerThread) {
- synchronized (this) {
- if (stopped) {
- remainingTime = time;
- } else {
- stop();
- remainingTime = time;
- cont();
- }
- }
- }
- }
-
- /**
- * In regular mode, a timer ticks at the specified interval,
- * regardless of how long the owner's tick() method takes.
- * While the timer is running, no ticks are ever discarded.
- * That means that if the owner's tick() method takes longer
- * than the interval, the ticks that would have occurred are
- * delivered immediately.
- *
- * In irregular mode, a timer starts delaying for exactly
- * the specified interval only after the tick() method returns.
- */
- public synchronized void setRegular(boolean regular) {
- this.regular = regular;
- }
-
- /*
- * This method is used only for testing purposes.
- */
- protected Thread getTimerThread() {
- return TimerThread.timerThread;
- }
-}
-
-
-/*
-
-This class implements the timer queue and is exclusively used by the
-Timer class. There are only two methods exported to the Timer class -
-enqueue, for inserting a timer into queue and dequeue, for removing
-a timer from the queue.
-
-A timer in the timer queue is awaiting a tick. When a timer is to be
-ticked, it is removed from the timer queue before the owner's tick()
-method is called.
-
-A single timer thread manages the timer queue. This timer thread
-looks at the head of the timer queue and delays until it's time for
-the timer to tick. When the time comes, the timer thread creates a
-callback thread to call the timer owner's tick() method. The timer
-thread then processes the next timer in the queue.
-
-When a timer is inserted at the head of the queue, the timer thread is
-notified. This causes the timer thread to prematurely wake up and
-process the new head of the queue.
-
-*/
-
-class TimerThread extends Thread {
- /*
- * Set to true to get debugging output.
- */
- public static boolean debug = false;
-
- /*
- * This is a handle to the thread managing the thread queue.
- */
- static TimerThread timerThread;
-
- /*
- * This flag is set if the timer thread has been notified
- * while it was in the timed wait. This flag allows the
- * timer thread to tell whether or not the wait completed.
- */
- static boolean notified = false;
-
- protected TimerThread() {
- super("TimerThread");
- timerThread = this;
- start();
- }
-
- public synchronized void run() {
- while (true) {
- long delay;
-
- while (timerQueue == null) {
- try {
- wait();
- } catch (InterruptedException ex) {
- // Just drop through and check timerQueue.
- }
- }
- notified = false;
- delay = timerQueue.sleepUntil - System.currentTimeMillis();
- if (delay > 0) {
- try {
- wait(delay);
- } catch (InterruptedException ex) {
- // Just drop through.
- }
- }
- // remove from timer queue.
- if (!notified) {
- Timer timer = timerQueue;
- timerQueue = timerQueue.next;
- TimerTickThread thr = TimerTickThread.call(
- timer, timer.sleepUntil);
- if (debug) {
- long delta = (System.currentTimeMillis() - timer.sleepUntil);
- System.out.println("tick(" + thr.getName() + ","
- + timer.interval + ","+delta+ ")");
- if (delta > 250) {
- System.out.println("*** BIG DELAY ***");
- }
- }
- }
- }
- }
-
- /* *******************************************************
- Timer Queue
- ******************************************************* */
-
- /*
- * The timer queue is a queue of timers waiting to tick.
- */
- static Timer timerQueue = null;
-
- /*
- * Uses timer.sleepUntil to determine where in the queue
- * to insert the timer object.
- * A new ticker thread is created only if the timer
- * is inserted at the beginning of the queue.
- * The timer must not already be in the queue.
- * Assumes the caller has the TimerThread monitor.
- */
- static protected void enqueue(Timer timer) {
- Timer prev = null;
- Timer cur = timerQueue;
-
- if (cur == null || timer.sleepUntil <= cur.sleepUntil) {
- // insert at front of queue
- timer.next = timerQueue;
- timerQueue = timer;
- notified = true;
- timerThread.notify();
- } else {
- do {
- prev = cur;
- cur = cur.next;
- } while (cur != null && timer.sleepUntil > cur.sleepUntil);
- // insert or append to the timer queue
- timer.next = cur;
- prev.next = timer;
- }
- if (debug) {
- long now = System.currentTimeMillis();
-
- System.out.print(Thread.currentThread().getName()
- + ": enqueue " + timer.interval + ": ");
- cur = timerQueue;
- while(cur != null) {
- long delta = cur.sleepUntil - now;
- System.out.print(cur.interval + "(" + delta + ") ");
- cur = cur.next;
- }
- System.out.println();
- }
- }
-
- /*
- * If the timer is not in the queue, returns false;
- * otherwise removes the timer from the timer queue and returns true.
- * Assumes the caller has the TimerThread monitor.
- */
- static protected boolean dequeue(Timer timer) {
- Timer prev = null;
- Timer cur = timerQueue;
-
- while (cur != null && cur != timer) {
- prev = cur;
- cur = cur.next;
- }
- if (cur == null) {
- if (debug) {
- System.out.println(Thread.currentThread().getName()
- + ": dequeue " + timer.interval + ": no-op");
- }
- return false;
- } if (prev == null) {
- timerQueue = timer.next;
- notified = true;
- timerThread.notify();
- } else {
- prev.next = timer.next;
- }
- timer.next = null;
- if (debug) {
- long now = System.currentTimeMillis();
-
- System.out.print(Thread.currentThread().getName()
- + ": dequeue " + timer.interval + ": ");
- cur = timerQueue;
- while(cur != null) {
- long delta = cur.sleepUntil - now;
- System.out.print(cur.interval + "(" + delta + ") ");
- cur = cur.next;
- }
- System.out.println();
- }
- return true;
- }
-
- /*
- * Inserts the timer back into the queue. This method
- * is used by a callback thread after it has called the
- * timer owner's tick() method. This method recomputes
- * the sleepUntil field.
- * Assumes the caller has the TimerThread and Timer monitor.
- */
- protected static void requeue(Timer timer) {
- if (!timer.stopped) {
- long now = System.currentTimeMillis();
- if (timer.regular) {
- timer.sleepUntil += timer.interval;
- } else {
- timer.sleepUntil = now + timer.interval;
- }
- enqueue(timer);
- } else if (debug) {
- System.out.println(Thread.currentThread().getName()
- + ": requeue " + timer.interval + ": no-op");
- }
- }
-}
-
-/*
-
-This class implements a simple thread whose only purpose is to call a
-timer owner's tick() method. A small fixed-sized pool of threads is
-maintained and is protected by the class monitor. If the pool is
-exhausted, a new thread is temporarily created and destroyed when
-done.
-
-A thread that's in the pool waits on it's own monitor. When the
-thread is retrieved from the pool, the retriever notifies the thread's
-monitor.
-
-*/
-
-class TimerTickThread extends Thread {
- /*
- * Maximum size of the thread pool.
- */
- static final int MAX_POOL_SIZE = 3;
-
- /*
- * Number of threads in the pool.
- */
- static int curPoolSize = 0;
-
- /*
- * The pool of timer threads.
- */
- static TimerTickThread pool = null;
-
- /*
- * Is used when linked into the thread pool.
- */
- TimerTickThread next = null;
-
- /*
- * This is the handle to the timer whose owner's
- * tick() method will be called.
- */
- Timer timer;
-
- /*
- * The value of a timer's sleepUntil value is captured here.
- * This is used to determine whether or not the timer should
- * be reinserted into the queue. If the timer's sleepUntil
- * value has changed, the timer is not reinserted.
- */
- long lastSleepUntil;
-
- /*
- * Creates a new callback thread to call the timer owner's
- * tick() method. A thread is taken from the pool if one
- * is available, otherwise, a new thread is created.
- * The thread handle is returned.
- */
- protected static synchronized TimerTickThread call(
- Timer timer, long sleepUntil) {
- TimerTickThread thread = pool;
-
- if (thread == null) {
- // create one.
- thread = new TimerTickThread();
- thread.timer = timer;
- thread.lastSleepUntil = sleepUntil;
- thread.start();
- } else {
- pool = pool.next;
- thread.timer = timer;
- thread.lastSleepUntil = sleepUntil;
- synchronized (thread) {
- thread.notify();
- }
- }
- return thread;
- }
-
- /*
- * Returns false if the thread should simply exit;
- * otherwise the thread is returned the pool, where
- * it waits to be notified. (I did try to use the
- * class monitor but the time between the notify
- * and breaking out of the wait seemed to take
- * significantly longer; need to look into this later.)
- */
- private boolean returnToPool() {
- synchronized (getClass()) {
- if (curPoolSize >= MAX_POOL_SIZE) {
- return false;
- }
- next = pool;
- pool = this;
- curPoolSize++;
- timer = null;
- }
- while (timer == null) {
- synchronized (this) {
- try {
- wait();
- } catch (InterruptedException ex) {
- // Just drop through and retest timer.
- }
- }
- }
- synchronized (getClass()) {
- curPoolSize--;
- }
- return true;
- }
-
- public void run() {
- do {
- timer.owner.tick(timer);
- synchronized (TimerThread.timerThread) {
- synchronized (timer) {
- if (lastSleepUntil == timer.sleepUntil) {
- TimerThread.requeue(timer);
- }
- }
- }
- } while (returnToPool());
- }
-}