Index: src/main/java/java/util/Timer.java =================================================================== --- src/main/java/java/util/Timer.java (revision 489282) +++ src/main/java/java/util/Timer.java (working copy) @@ -44,16 +44,16 @@ */ public class Timer { - private static final class TimerImpl extends Thread { + private static final class TimerImpl extends Thread { - private static final class TimerNode { - TimerNode parent, left, right; + private static final class TimerNode { + TimerNode parent, left, right; - TimerTask task; + TimerTask task; - public TimerNode(TimerTask value) { - this.task = value; - } + public TimerNode(TimerTask value) { + this.task = value; + } public void deleteIfCancelled(TimerTree tasks) { @@ -68,120 +68,120 @@ if (right != null) { right.deleteIfCancelled(tasks); } - if (task.isCancelled()) { + if (task.cancelled) { tasks.delete(this); tasks.deletedCancelledNumber++; } } } - private static final class TimerTree { + private static final class TimerTree { int deletedCancelledNumber; - TimerNode root; + TimerNode root; - boolean isEmpty() { - return root == null; - } + boolean isEmpty() { + return root == null; + } - void insert(TimerNode z) { - TimerNode y = null, x = root; - while (x != null) { - y = x; - if (z.task.when < x.task.when) { + void insert(TimerNode z) { + TimerNode y = null, x = root; + while (x != null) { + y = x; + if (z.task.getWhen() < x.task.getWhen()) { x = x.left; } else { x = x.right; } - } - z.parent = y; - if (y == null) { + } + z.parent = y; + if (y == null) { root = z; - } else if (z.task.when < y.task.when) { + } else if (z.task.getWhen() < y.task.getWhen()) { y.left = z; } else { y.right = z; } - } + } - void delete(TimerNode z) { - TimerNode y = null, x = null; - if (z.left == null || z.right == null) { + void delete(TimerNode z) { + TimerNode y = null, x = null; + if (z.left == null || z.right == null) { y = z; } else { y = successor(z); } - if (y.left != null) { + if (y.left != null) { x = y.left; } else { x = y.right; } - if (x != null) { + if (x != null) { x.parent = y.parent; } - if (y.parent == null) { + if (y.parent == null) { root = x; } else if (y == y.parent.left) { y.parent.left = x; } else { y.parent.right = x; } - if (y != z) { + if (y != z) { z.task = y.task; } - } + } - private TimerNode successor(TimerNode x) { - if (x.right != null) { + private TimerNode successor(TimerNode x) { + if (x.right != null) { return minimum(x.right); } - TimerNode y = x.parent; - while (y != null && x == y.right) { - x = y; - y = y.parent; - } - return y; - } + TimerNode y = x.parent; + while (y != null && x == y.right) { + x = y; + y = y.parent; + } + return y; + } - private TimerNode minimum(TimerNode x) { - while (x.left != null) { + private TimerNode minimum(TimerNode x) { + while (x.left != null) { x = x.left; } - return x; - } + return x; + } - TimerNode minimum() { - return minimum(root); - } - } + TimerNode minimum() { + return minimum(root); + } + } - /** - * True if the method cancel() of the Timer was called or the !!!stop() - * method was invoked - */ - private boolean cancelled; + /** + * True if the method cancel() of the Timer was called or the !!!stop() + * method was invoked + */ + private boolean cancelled; - /** - * True if the Timer has become garbage - */ - private boolean finished; + /** + * True if the Timer has become garbage + */ + private boolean finished; - /** - * Vector consists of scheduled events, sorted according to - * when field of TaskScheduled object. - */ - private TimerTree tasks = new TimerTree(); + /** + * Vector consists of scheduled events, sorted according to + * when field of TaskScheduled object. + */ + private TimerTree tasks = new TimerTree(); - /** - * Starts a new timer. - * - * @param isDaemon - */ - TimerImpl(boolean isDaemon) { - this.setDaemon(isDaemon); - this.start(); - } + /** + * Starts a new timer. + * + * @param isDaemon + */ + TimerImpl(boolean isDaemon) { + this.setDaemon(isDaemon); + this.start(); + } TimerImpl(String name, boolean isDaemon) { this.setName(name); @@ -189,102 +189,113 @@ this.start(); } - /** - * This method will be launched on separate thread for each Timer - * object. - */ - @Override + /** + * This method will be launched on separate thread for each Timer + * object. + */ + @Override public void run() { - while (true) { - TimerTask task; - synchronized (this) { - // need to check cancelled inside the synchronized block - if (cancelled) { + while (true) { + TimerTask task; + synchronized (this) { + // need to check cancelled inside the synchronized block + if (cancelled) { return; } - if (tasks.isEmpty()) { - if (finished) { + if (tasks.isEmpty()) { + if (finished) { return; } - // no tasks scheduled -- sleep until any task appear - try { - this.wait(); - } catch (Exception e) { - } - continue; - } + // no tasks scheduled -- sleep until any task appear + try { + this.wait(); + } catch (Exception e) { + } + continue; + } - long currentTime = System.currentTimeMillis(); + long currentTime = System.currentTimeMillis(); - TimerNode taskNode = tasks.minimum(); - task = taskNode.task; - if (task.isCancelled()) { - tasks.delete(taskNode); - continue; - } + TimerNode taskNode = tasks.minimum(); + task = taskNode.task; + long timeToSleep; - // check the time to sleep for the first task scheduled - long timeToSleep = task.when - currentTime; + synchronized (task.lock) { + if (task.cancelled) { + tasks.delete(taskNode); + continue; + } - if (timeToSleep > 0) { - // sleep! - try { - this.wait(timeToSleep); - } catch (Exception e) { - } - continue; - } + // check the time to sleep for the first task scheduled + timeToSleep = task.when - currentTime; + } - // no sleep is necessary before launching the task + if (timeToSleep > 0) { + // sleep! + try { + this.wait(timeToSleep); + } catch (Exception e) { + } + continue; + } - // set time to schedule - task.setScheduledTime(task.when); + // no sleep is necessary before launching the task - // remove task from queue - tasks.delete(taskNode); + synchronized (task.lock) { + if (task.cancelled) { + tasks.delete(taskNode); + continue; + } - // set when the next task should be launched - if (task.period >= 0) { - // this is a repeating task, - if (task.fixedRate) { - // task is scheduled at fixed rate - task.when = task.when + task.period; - } else { - // task is scheduled at fixed delay - task.when = System.currentTimeMillis() - + task.period; - } + // set time to schedule + task.setScheduledTime(task.when); - // insert this task into queue - insertTask(task); - } else { - task.when = 0; + // remove task from queue + tasks.delete(taskNode); + + // set when the next task should be launched + if (task.period >= 0) { + // this is a repeating task, + if (task.fixedRate) { + // task is scheduled at fixed rate + task.when = task.when + task.period; + } else { + // task is scheduled at fixed delay + task.when = System.currentTimeMillis() + + task.period; + } + + // insert this task into queue + insertTask(task); + } else { + task.when = 0; + } } - } + } - // run the task - try { - task.run(); - } catch (Exception e) { - } - } - } + // run the task + try { + task.run(); + } catch (Exception e) { + } + } + } - private void insertTask(TimerTask newTask) { - // callers are synchronized - tasks.insert(new TimerNode(newTask)); - this.notify(); - } + private void insertTask(TimerTask newTask) { + // callers are synchronized + tasks.insert(new TimerNode(newTask)); + this.notify(); + } - /** - * Cancels timer. - */ - public synchronized void cancel() { - cancelled = true; - tasks = new TimerTree(); - this.notify(); - } + /** + * Cancels timer. + */ + public synchronized void cancel() { + cancelled = true; + tasks = new TimerTree(); + this.notify(); + } public int purge() { if(tasks.isEmpty()) { @@ -297,37 +308,37 @@ } } - /* This object will be used in synchronization purposes */ - private TimerImpl impl; + /* This object will be used in synchronization purposes */ + private TimerImpl impl; - // Used to finalize thread - @SuppressWarnings("unused") + // Used to finalize thread + @SuppressWarnings("unused") private Object finalizer = new Object() { //$NON-LOCK-1$ - @Override + @Override public void finalize() { - synchronized (impl) { - impl.finished = true; - impl.notify(); - } - } - }; + synchronized (impl) { + impl.finished = true; + impl.notify(); + } + } + }; - /** - * Creates a new Timer which may be specified to be run as a Daemon Thread. - * - * @param isDaemon - * true if Timers thread should be a daemon thread. - */ - public Timer(boolean isDaemon) { - impl = new TimerImpl(isDaemon); - } + /** + * Creates a new Timer which may be specified to be run as a Daemon Thread. + * + * @param isDaemon + * true if Timers thread should be a daemon thread. + */ + public Timer(boolean isDaemon) { + impl = new TimerImpl(isDaemon); + } - /** - * Creates a new non-daemon Timer. - */ - public Timer() { - impl = new TimerImpl(false); - } + /** + * Creates a new non-daemon Timer. + */ + public Timer() { + impl = new TimerImpl(false); + } public Timer(String name, boolean isDaemon) { impl = new TimerImpl(name, isDaemon); @@ -337,14 +348,14 @@ impl = new TimerImpl(name, false); } - /** + /** * Cancels the Timer and removed any scheduled tasks. If there is a * currently running task it is not effected. No more tasks may be scheduled * on this Timer. Subsequent calls do nothing. */ - public void cancel() { - impl.cancel(); - } + public void cancel() { + impl.cancel(); + } public int purge() { synchronized (impl) { @@ -352,186 +363,188 @@ } } - /** - * Schedule a task for single execution. If when is less than the current - * time, it will be scheduled to executed as soon as possible. - * - * @param task - * The task to schedule - * @param when - * Time of execution - * - * @exception IllegalArgumentException - * if when.getTime() < 0 - * @exception IllegalStateException - * if the timer has been cancelled, the task has been - * scheduled or cancelled. - */ - public void schedule(TimerTask task, Date when) { - if (when.getTime() < 0) { + /** + * Schedule a task for single execution. If when is less than the current + * time, it will be scheduled to executed as soon as possible. + * + * @param task + * The task to schedule + * @param when + * Time of execution + * + * @exception IllegalArgumentException + * if when.getTime() < 0 + * @exception IllegalStateException + * if the timer has been cancelled, the task has been + * scheduled or cancelled. + */ + public void schedule(TimerTask task, Date when) { + if (when.getTime() < 0) { throw new IllegalArgumentException(); } - long delay = when.getTime() - System.currentTimeMillis(); - scheduleImpl(task, delay < 0 ? 0 : delay, -1, false); - } + long delay = when.getTime() - System.currentTimeMillis(); + scheduleImpl(task, delay < 0 ? 0 : delay, -1, false); + } - /** - * Schedule a task for single execution after a specific delay. - * - * @param task - * The task to schedule - * @param delay - * Amount of time before execution - * - * @exception IllegalArgumentException - * if delay < 0 - * @exception IllegalStateException - * if the timer has been cancelled, the task has been - * scheduled or cancelled. - */ - public void schedule(TimerTask task, long delay) { - if (delay < 0) { + /** + * Schedule a task for single execution after a specific delay. + * + * @param task + * The task to schedule + * @param delay + * Amount of time before execution + * + * @exception IllegalArgumentException + * if delay < 0 + * @exception IllegalStateException + * if the timer has been cancelled, the task has been + * scheduled or cancelled. + */ + public void schedule(TimerTask task, long delay) { + if (delay < 0) { throw new IllegalArgumentException(); } - scheduleImpl(task, delay, -1, false); - } + scheduleImpl(task, delay, -1, false); + } - /** - * Schedule a task for repeated fix-delay execution after a specific delay. - * - * @param task - * The task to schedule - * @param delay - * Amount of time before first execution - * @param period - * Amount of time between subsequent executions - * - * @exception IllegalArgumentException - * if delay < 0 or period < 0 - * @exception IllegalStateException - * if the timer has been cancelled, the task has been - * scheduled or cancelled. - */ - public void schedule(TimerTask task, long delay, long period) { - if (delay < 0 || period <= 0) { + /** + * Schedule a task for repeated fix-delay execution after a specific delay. + * + * @param task + * The task to schedule + * @param delay + * Amount of time before first execution + * @param period + * Amount of time between subsequent executions + * + * @exception IllegalArgumentException + * if delay < 0 or period < 0 + * @exception IllegalStateException + * if the timer has been cancelled, the task has been + * scheduled or cancelled. + */ + public void schedule(TimerTask task, long delay, long period) { + if (delay < 0 || period <= 0) { throw new IllegalArgumentException(); } - scheduleImpl(task, delay, period, false); - } + scheduleImpl(task, delay, period, false); + } - /** - * Schedule a task for repeated fix-delay execution after a specific time - * has been reached. - * - * @param task - * The task to schedule - * @param when - * Time of first execution - * @param period - * Amount of time between subsequent executions - * - * @exception IllegalArgumentException - * if when.getTime() < 0 or period < 0 - * @exception IllegalStateException - * if the timer has been cancelled, the task has been - * scheduled or cancelled. - */ - public void schedule(TimerTask task, Date when, long period) { - if (period <= 0 || when.getTime() < 0) { - throw new IllegalArgumentException(); - } - long delay = when.getTime() - System.currentTimeMillis(); - scheduleImpl(task, delay < 0 ? 0 : delay, period, false); - } + /** + * Schedule a task for repeated fix-delay execution after a specific time + * has been reached. + * + * @param task + * The task to schedule + * @param when + * Time of first execution + * @param period + * Amount of time between subsequent executions + * + * @exception IllegalArgumentException + * if when.getTime() < 0 or period < 0 + * @exception IllegalStateException + * if the timer has been cancelled, the task has been + * scheduled or cancelled. + */ + public void schedule(TimerTask task, Date when, long period) { + if (period <= 0 || when.getTime() < 0) { + throw new IllegalArgumentException(); + } + long delay = when.getTime() - System.currentTimeMillis(); + scheduleImpl(task, delay < 0 ? 0 : delay, period, false); + } - /** - * Schedule a task for repeated fixed-rate execution after a specific delay - * has been happened. The difference of fixed-rate is that it may bunch up - * subsequent task runs to try to get the task repeating at it's desired - * time. - * - * @param task - * The task to schedule - * @param delay - * Amount of time before first execution - * @param period - * Amount of time between subsequent executions - * - * @exception IllegalArgumentException - * if delay < 0 or period < 0 - * @exception IllegalStateException - * if the timer has been cancelled, the task has been - * scheduled or cancelled. - */ - public void scheduleAtFixedRate(TimerTask task, long delay, long period) { - if (delay < 0 || period <= 0) { + /** + * Schedule a task for repeated fixed-rate execution after a specific delay + * has been happened. The difference of fixed-rate is that it may bunch up + * subsequent task runs to try to get the task repeating at it's desired + * time. + * + * @param task + * The task to schedule + * @param delay + * Amount of time before first execution + * @param period + * Amount of time between subsequent executions + * + * @exception IllegalArgumentException + * if delay < 0 or period < 0 + * @exception IllegalStateException + * if the timer has been cancelled, the task has been + * scheduled or cancelled. + */ + public void scheduleAtFixedRate(TimerTask task, long delay, long period) { + if (delay < 0 || period <= 0) { throw new IllegalArgumentException(); } - scheduleImpl(task, delay, period, true); - } + scheduleImpl(task, delay, period, true); + } - /** - * Schedule a task for repeated fixed-rate execution after a specific time - * has been reached. The difference of fixed-rate is that it may bunch up - * subsequent task runs to try to get the task repeating at it's desired - * time. - * - * @param task - * The task to schedule - * @param when - * Time of first execution - * @param period - * Amount of time between subsequent executions - * - * @exception IllegalArgumentException - * if when.getTime() < 0 or period < 0 - * @exception IllegalStateException - * if the timer has been cancelled, the task has been - * scheduled or cancelled. - */ - public void scheduleAtFixedRate(TimerTask task, Date when, long period) { - if (period <= 0 || when.getTime() < 0) { + /** + * Schedule a task for repeated fixed-rate execution after a specific time + * has been reached. The difference of fixed-rate is that it may bunch up + * subsequent task runs to try to get the task repeating at it's desired + * time. + * + * @param task + * The task to schedule + * @param when + * Time of first execution + * @param period + * Amount of time between subsequent executions + * + * @exception IllegalArgumentException + * if when.getTime() < 0 or period < 0 + * @exception IllegalStateException + * if the timer has been cancelled, the task has been + * scheduled or cancelled. + */ + public void scheduleAtFixedRate(TimerTask task, Date when, long period) { + if (period <= 0 || when.getTime() < 0) { throw new IllegalArgumentException(); } - long delay = when.getTime() - System.currentTimeMillis(); - scheduleImpl(task, delay < 0 ? 0 : delay, period, true); - } + long delay = when.getTime() - System.currentTimeMillis(); + scheduleImpl(task, delay < 0 ? 0 : delay, period, true); + } - /** - * Schedule a task. - * - * @param task - * @param delay - * @param period - * @param fixed - */ - private void scheduleImpl(TimerTask task, long delay, long period, - boolean fixed) { - synchronized (impl) { - if (impl.cancelled) { + /** + * Schedule a task. + * + * @param task + * @param delay + * @param period + * @param fixed + */ + private void scheduleImpl(TimerTask task, long delay, long period, + boolean fixed) { + synchronized (impl) { + if (impl.cancelled) { throw new IllegalStateException(Msg.getString("K00f3")); //$NON-NLS-1$ } - long when = delay + System.currentTimeMillis(); + long when = delay + System.currentTimeMillis(); - if (when < 0) { + if (when < 0) { throw new IllegalArgumentException(Msg.getString("K00f5")); //$NON-NLS-1$ } - if (task.isScheduled()) { - throw new IllegalStateException(Msg.getString("K00f6")); //$NON-NLS-1$ - } + synchronized (task.lock) { + if (task.isScheduled()) { + throw new IllegalStateException(Msg.getString("K00f6")); //$NON-NLS-1$ + } - if (task.isCancelled()) { - throw new IllegalStateException(Msg.getString("K00f7")); //$NON-NLS-1$ + if (task.cancelled) { + throw new IllegalStateException(Msg.getString("K00f7")); //$NON-NLS-1$ + } + + task.when = when; + task.period = period; + task.fixedRate = fixed; } - task.when = when; - task.period = period; - task.fixedRate = fixed; - - // insert the newTask into queue - impl.insertTask(task); - } - } + // insert the newTask into queue + impl.insertTask(task); + } + } } Index: src/main/java/java/util/TimerTask.java =================================================================== --- src/main/java/java/util/TimerTask.java (revision 489282) +++ src/main/java/java/util/TimerTask.java (working copy) @@ -25,84 +25,93 @@ * @see java.lang.Object#wait(long) */ public abstract class TimerTask implements Runnable { + /* Lock object for synchronization. It's also used by Timer class. */ + final Object lock = new Object(); - /* If timer was cancelled */ - private boolean cancelled; + /* If timer was cancelled */ + boolean cancelled; - /* Slots used by Timer */ - long when; + /* Slots used by Timer */ + long when; - long period; + long period; - boolean fixedRate; + boolean fixedRate; - /* - * The time when task will be executed, or the time when task was launched - * if this is task in progress. - */ - private long scheduledTime; + /* + * The time when task will be executed, or the time when task was launched + * if this is task in progress. + */ + private long scheduledTime; - /* - * Method called from the Timer object when scheduling an event - * @param time - */ - void setScheduledTime(long time) { - scheduledTime = time; - } + /* + * Method called from the Timer for synchronized getting of when field. + */ + long getWhen() { + synchronized (lock) { + return when; + } + } + + /* + * Method called from the Timer object when scheduling an event + * @param time + */ + void setScheduledTime(long time) { + synchronized (lock) { + scheduledTime = time; + } + } - /* - * Is TimerTask scheduled into any timer? - * - * @return true if the timer task is scheduled, - * false otherwise. - */ - boolean isScheduled() { - return when > 0 || scheduledTime > 0; - } + /* + * Is TimerTask scheduled into any timer? + * + * @return true if the timer task is scheduled, + * false otherwise. + */ + boolean isScheduled() { + synchronized (lock) { + return when > 0 || scheduledTime > 0; + } + } - /* - * Is TimerTask cancelled? - * - * @return true if the timer task is cancelled, - * false otherwise. - */ - boolean isCancelled() { - return cancelled; - } + protected TimerTask() { + super(); + } - protected TimerTask() { - super(); - } + /** + * Cancels the Task and removes it from the Timer's queue. Generally, it + * returns false if the call did not prevent a TimerTask from running at + * least once. Subsequent calls have no effect. + * + * @return true if the call prevented a scheduled execution + * from taking place, false otherwise. + */ + public boolean cancel() { + synchronized (lock) { + boolean willRun = !cancelled && when > 0; + cancelled = true; + return willRun; + } + } - /** - * Cancels the Task and removes it from the Timer's queue. Generally, it - * returns false if the call did not prevent a TimerTask from running at - * least once. Subsequent calls have no effect. - * - * @return true if the call prevented a scheduled execution - * from taking place, false otherwise. - */ - public boolean cancel() { - boolean willRun = !cancelled && when > 0; - cancelled = true; - return willRun; - } + /** + * Returns the scheduled execution time. If the task execution is in + * progress returns the execution time of ongoing task. Tasks which have not + * yet run return an undefined value. + * + * @return the most recent execution time. + */ + public long scheduledExecutionTime() { + synchronized (lock) { + return scheduledTime; + } + } - /** - * Returns the scheduled execution time. If the task execution is in - * progress returns the execution time of ongoing task. Tasks which have not - * yet run return an undefined value. - * - * @return the most recent execution time. - */ - public long scheduledExecutionTime() { - return scheduledTime; - } + /** + * The task to run should be specified in the implementation of the run() + * method. + */ + public abstract void run(); - /** - * The task to run should be specified in the implementation of the run() - * method. - */ - public abstract void run(); - }