diff -r aade36e70da0 -r e2bf17cee34b jdk/src/share/classes/sun/misc/Timer.java --- a/jdk/src/share/classes/sun/misc/Timer.java Wed Jun 11 10:53:27 2014 +0400 +++ /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: - -
-    class Main implements Timeable {
-        public void tick(Timer timer) {
-            System.out.println("tick");
-        }
-        public static void main(String args[]) {
-            (new Timer(this, 5000)).cont();
-        }
-    }
-    
- - 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()); - } -}