From bb684b3ae96581f86b0391d1db4187f9a03d7b48 Mon Sep 17 00:00:00 2001 From: Sergey Labutin Date: Thu, 31 Aug 2017 01:56:02 +0300 Subject: [PATCH 1/2] update timer --- jtransc-rt/src/java/util/Timer.java | 750 ++++++------------ jtransc-rt/src/java/util/TimerTask.java | 194 +++-- .../ScheduledThreadPoolExecutor.java | 55 +- 3 files changed, 375 insertions(+), 624 deletions(-) diff --git a/jtransc-rt/src/java/util/Timer.java b/jtransc-rt/src/java/util/Timer.java index 25ac4322..91bdd72b 100644 --- a/jtransc-rt/src/java/util/Timer.java +++ b/jtransc-rt/src/java/util/Timer.java @@ -1,588 +1,298 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package java.util; - -/** - * Timers schedule one-shot or recurring {@link TimerTask tasks} for execution. - * Prefer {@link java.util.concurrent.ScheduledThreadPoolExecutor - * ScheduledThreadPoolExecutor} for new code. * - *

Each timer has one thread on which tasks are executed sequentially. When - * this thread is busy running a task, runnable tasks may be subject to delays. * - *

One-shot are scheduled to run at an absolute time or after a relative - * delay. * - *

Recurring tasks are scheduled with either a fixed period or a fixed rate: - *

* - *

When a timer is no longer needed, users should call {@link #cancel}, which - * releases the timer's thread and other resources. Timers not explicitly - * cancelled may hold resources indefinitely. * - *

This class does not offer guarantees about the real-time nature of task - * scheduling. Multiple threads can share a single timer without - * synchronization. */ -public class Timer { - private static final class TimerImpl extends Thread { +package java.util; +import java.util.concurrent.atomic.AtomicInteger; - private static final class TimerHeap { - private int DEFAULT_HEAP_SIZE = 256; +public class Timer { - private TimerTask[] timers = new TimerTask[DEFAULT_HEAP_SIZE]; + private final TaskQueue queue = new TaskQueue(); + private final TimerThread thread = new TimerThread(queue); + private final static AtomicInteger nextSerialNumber = new AtomicInteger(0); - private int size = 0; + private static int serialNumber() { + return nextSerialNumber.getAndIncrement(); + } - private int deletedCancelledNumber = 0; + public Timer() { + this("Timer-" + serialNumber()); + } - public TimerTask minimum() { - return timers[0]; - } + public Timer(boolean isDaemon) { + this("Timer-" + serialNumber(), isDaemon); + } - public boolean isEmpty() { - return size == 0; - } + public Timer(String name) { + thread.setName(name); + thread.start(); + } - public void insert(TimerTask task) { - if (timers.length == size) { - TimerTask[] appendedTimers = new TimerTask[size * 2]; - System.arraycopy(timers, 0, appendedTimers, 0, size); - timers = appendedTimers; - } - timers[size++] = task; - upHeap(); - } + public Timer(String name, boolean isDaemon) { + thread.setName(name); + thread.setDaemon(isDaemon); + thread.start(); + } - public void delete(int pos) { - // posible to delete any position of the heap - if (pos >= 0 && pos < size) { - timers[pos] = timers[--size]; - timers[size] = null; - downHeap(pos); - } - } + public void schedule(TimerTask task, long delay) { + if (delay < 0) + throw new IllegalArgumentException("Negative delay."); + sched(task, System.currentTimeMillis()+delay, 0); + } - private void upHeap() { - int current = size - 1; - int parent = (current - 1) / 2; + public void schedule(TimerTask task, Date time) { + sched(task, time.getTime(), 0); + } - while (timers[current].when < timers[parent].when) { - // swap the two - TimerTask tmp = timers[current]; - timers[current] = timers[parent]; - timers[parent] = tmp; + public void schedule(TimerTask task, long delay, long period) { + if (delay < 0) + throw new IllegalArgumentException("Negative delay."); + if (period <= 0) + throw new IllegalArgumentException("Non-positive period."); + sched(task, System.currentTimeMillis()+delay, -period); + } - // update pos and current - current = parent; - parent = (current - 1) / 2; - } - } + public void schedule(TimerTask task, Date firstTime, long period) { + if (period <= 0) + throw new IllegalArgumentException("Non-positive period."); + sched(task, firstTime.getTime(), -period); + } - private void downHeap(int pos) { - int current = pos; - int child = 2 * current + 1; - - while (child < size && size > 0) { - // compare the children if they exist - if (child + 1 < size - && timers[child + 1].when < timers[child].when) { - child++; - } - - // compare selected child with parent - if (timers[current].when < timers[child].when) { - break; - } - - // swap the two - TimerTask tmp = timers[current]; - timers[current] = timers[child]; - timers[child] = tmp; - - // update pos and current - current = child; - child = 2 * current + 1; - } - } + public void scheduleAtFixedRate(TimerTask task, long delay, long period) { + if (delay < 0) + throw new IllegalArgumentException("Negative delay."); + if (period <= 0) + throw new IllegalArgumentException("Non-positive period."); + sched(task, System.currentTimeMillis()+delay, period); + } - public void reset() { - timers = new TimerTask[DEFAULT_HEAP_SIZE]; - size = 0; - } + public void scheduleAtFixedRate(TimerTask task, Date firstTime, + long period) { + if (period <= 0) + throw new IllegalArgumentException("Non-positive period."); + sched(task, firstTime.getTime(), period); + } - public void adjustMinimum() { - downHeap(0); - } + private void sched(TimerTask task, long time, long period) { + if (time < 0) + throw new IllegalArgumentException("Illegal execution time."); - public void deleteIfCancelled() { - for (int i = 0; i < size; i++) { - if (timers[i].cancelled) { - deletedCancelledNumber++; - delete(i); - // re-try this point - i--; - } - } - } + if (Math.abs(period) > (Long.MAX_VALUE >> 1)) + period >>= 1; - private int getTask(TimerTask task) { - for (int i = 0; i < timers.length; i++) { - if (timers[i] == task) { - return i; - } - } - return -1; + synchronized(queue) { + if (!thread.newTasksMayBeScheduled) + throw new IllegalStateException("Timer already cancelled."); + + synchronized(task.lock) { + if (task.state != TimerTask.VIRGIN) { + throw new IllegalStateException("Task already scheduled or cancelled"); + } + task.nextExecutionTime = time; + task.period = period; + task.state = TimerTask.SCHEDULED; } + queue.add(task); + if (queue.getMin() == task) + queue.notify(); } + } - /** - * 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; - - /** - * Contains scheduled events, sorted according to - * {@code when} field of TaskScheduled object. - */ - private TimerHeap tasks = new TimerHeap(); - - /** - * Starts a new timer. - * - * @param name thread's name - * @param isDaemon daemon thread or not - */ - TimerImpl(String name, boolean isDaemon) { - this.setName(name); - this.setDaemon(isDaemon); - this.start(); + public void cancel() { + synchronized(queue) { + thread.newTasksMayBeScheduled = false; + queue.clear(); + queue.notify(); // In case queue was already empty. } + } - /** - * 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) { - return; - } - if (tasks.isEmpty()) { - if (finished) { - return; - } - // no tasks scheduled -- sleep until any task appear - try { - this.wait(); - } catch (InterruptedException ignored) { - } - continue; - } - - long currentTime = System.currentTimeMillis(); - - task = tasks.minimum(); - long timeToSleep; - - synchronized (task.lock) { - if (task.cancelled) { - tasks.delete(0); - continue; - } - - // check the time to sleep for the first task scheduled - timeToSleep = task.when - currentTime; - } - - if (timeToSleep > 0) { - // sleep! - try { - this.wait(timeToSleep); - } catch (InterruptedException ignored) { - } - continue; - } - - // no sleep is necessary before launching the task - - synchronized (task.lock) { - int pos = 0; - if (tasks.minimum().when != task.when) { - pos = tasks.getTask(task); - } - if (task.cancelled) { - tasks.delete(tasks.getTask(task)); - continue; - } - - // set time to schedule - task.setScheduledTime(task.when); - - // remove task from queue - tasks.delete(pos); - - // 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; - } - } - } - - boolean taskCompletedNormally = false; - try { - task.run(); - taskCompletedNormally = true; - } finally { - if (!taskCompletedNormally) { - synchronized (this) { - cancelled = true; - } - } - } - } - } + public int purge() { + int result = 0; - private void insertTask(TimerTask newTask) { - // callers are synchronized - tasks.insert(newTask); - this.notify(); - } + synchronized(queue) { + for (int i = queue.size(); i > 0; i--) { + if (queue.get(i).state == TimerTask.CANCELLED) { + queue.quickRemove(i); + result++; + } + } - /** - * Cancels timer. - */ - public synchronized void cancel() { - cancelled = true; - tasks.reset(); - this.notify(); - } + if (result != 0) + queue.heapify(); + } - public int purge() { - if (tasks.isEmpty()) { - return 0; - } - // callers are synchronized - tasks.deletedCancelledNumber = 0; - tasks.deleteIfCancelled(); - return tasks.deletedCancelledNumber; - } + return result; + } +} - } +class TimerThread extends Thread { + boolean newTasksMayBeScheduled = true; + private TaskQueue queue; + + TimerThread(TaskQueue queue) { + this.queue = queue; + } + + public void run() { + try { + mainLoop(); + } finally { + // Someone killed this Thread, behave as if Timer cancelled + synchronized (queue) { + newTasksMayBeScheduled = false; + queue.clear(); // Eliminate obsolete references + } + } + } + + private void mainLoop() { + while (true) { + try { + if (!newTasksMayBeScheduled) { + return; + } + + boolean taskFired = false; + TimerTask task = null; + + synchronized (queue) { + if (!queue.isEmpty()) { + long currentTime, executionTime; + task = queue.getMin(); + synchronized (task.lock) { + if (task.state == TimerTask.CANCELLED) { + queue.removeMin(); + continue; // No action required, poll queue again + } + currentTime = System.currentTimeMillis(); + executionTime = task.nextExecutionTime; + + if (taskFired = (executionTime <= currentTime)) { + if (task.period == 0) { // Non-repeating, remove + queue.removeMin(); + task.state = TimerTask.EXECUTED; + } else { // Repeating task, reschedule + queue.rescheduleMin(task.period < 0 ? currentTime - task.period : executionTime + task.period); + } + } + } + } + } + + if (!taskFired) { // Task hasn't yet fired; wait + Thread.sleep(50); + } else if (task != null) { + task.run(); + } + } catch (InterruptedException e) { + } + } + } +} - private static final class FinalizerHelper { - private final TimerImpl impl; +class TaskQueue { - FinalizerHelper(TimerImpl impl) { - this.impl = impl; - } + private TimerTask[] queue = new TimerTask[128]; + private int size = 0; - @Override protected void finalize() throws Throwable { - try { - synchronized (impl) { - impl.finished = true; - impl.notify(); - } - } finally { - super.finalize(); - } - } + int size() { + return size; } - private static long timerId; + void add(TimerTask task) { + // Grow backing store if necessary + if (size + 1 == queue.length) + queue = Arrays.copyOf(queue, 2*queue.length); - private synchronized static long nextId() { - return timerId++; + queue[++size] = task; + fixUp(size); } - /* This object will be used in synchronization purposes */ - private final TimerImpl impl; - - // Used to finalize thread - @SuppressWarnings("unused") - private final FinalizerHelper finalizer; - - /** - * Creates a new named {@code Timer} which may be specified to be run as a - * daemon thread. - * - * @param name the name of the {@code Timer}. - * @param isDaemon true if {@code Timer}'s thread should be a daemon thread. - * @throws NullPointerException is {@code name} is {@code null} - */ - public Timer(String name, boolean isDaemon) { - if (name == null) { - throw new NullPointerException("name == null"); - } - this.impl = new TimerImpl(name, isDaemon); - this.finalizer = new FinalizerHelper(impl); + TimerTask getMin() { + return queue[1]; } - /** - * Creates a new named {@code Timer} which does not run as a daemon thread. - * - * @param name the name of the Timer. - * @throws NullPointerException is {@code name} is {@code null} - */ - public Timer(String name) { - this(name, false); - } - - /** - * Creates a new {@code Timer} which may be specified to be run as a daemon thread. - * - * @param isDaemon {@code true} if the {@code Timer}'s thread should be a daemon thread. - */ - public Timer(boolean isDaemon) { - this("Timer-" + Timer.nextId(), isDaemon); + TimerTask get(int i) { + return queue[i]; } - /** - * Creates a new non-daemon {@code Timer}. - */ - public Timer() { - this(false); + void removeMin() { + queue[1] = queue[size]; + queue[size--] = null; // Drop extra reference to prevent memory leak + fixDown(1); } - /** - * Cancels the {@code Timer} and all scheduled tasks. If there is a - * currently running task it is not affected. No more tasks may be scheduled - * on this {@code Timer}. Subsequent calls do nothing. - */ - public void cancel() { - impl.cancel(); - } + void quickRemove(int i) { + assert i <= size; - /** - * Removes all canceled tasks from the task queue. If there are no - * other references on the tasks, then after this call they are free - * to be garbage collected. - * - * @return the number of canceled tasks that were removed from the task - * queue. - */ - public int purge() { - synchronized (impl) { - return impl.purge(); - } + queue[i] = queue[size]; + queue[size--] = null; // Drop extra ref to prevent memory leak } - /** - * Schedule a task for single execution. If {@code when} is less than the - * current time, it will be scheduled to be executed as soon as possible. - * - * @param task - * the task to schedule. - * @param when - * time of execution. - * @throws IllegalArgumentException - * if {@code when.getTime() < 0}. - * @throws IllegalStateException - * if the {@code Timer} has been canceled, or if the task has been - * scheduled or canceled. - */ - public void schedule(TimerTask task, Date when) { - if (when.getTime() < 0) { - throw new IllegalArgumentException("when < 0: " + when.getTime()); - } - long delay = when.getTime() - System.currentTimeMillis(); - scheduleImpl(task, delay < 0 ? 0 : delay, -1, false); + void rescheduleMin(long newTime) { + queue[1].nextExecutionTime = newTime; + fixDown(1); } - /** - * Schedule a task for single execution after a specified delay. - * - * @param task - * the task to schedule. - * @param delay - * amount of time in milliseconds before execution. - * @throws IllegalArgumentException - * if {@code delay < 0}. - * @throws IllegalStateException - * if the {@code Timer} has been canceled, or if the task has been - * scheduled or canceled. - */ - public void schedule(TimerTask task, long delay) { - if (delay < 0) { - throw new IllegalArgumentException("delay < 0: " + delay); - } - scheduleImpl(task, delay, -1, false); + boolean isEmpty() { + return size==0; } - /** - * Schedule a task for repeated fixed-delay execution after a specific delay. - * - * @param task - * the task to schedule. - * @param delay - * amount of time in milliseconds before first execution. - * @param period - * amount of time in milliseconds between subsequent executions. - * @throws IllegalArgumentException - * if {@code delay < 0} or {@code period <= 0}. - * @throws IllegalStateException - * if the {@code Timer} has been canceled, or if the task has been - * scheduled or canceled. - */ - public void schedule(TimerTask task, long delay, long period) { - if (delay < 0 || period <= 0) { - throw new IllegalArgumentException(); - } - scheduleImpl(task, delay, period, false); - } + void clear() { + // Null out task references to prevent memory leak + for (int i=1; i<=size; i++) + queue[i] = null; - /** - * Schedule a task for repeated fixed-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 in milliseconds between subsequent executions. - * @throws IllegalArgumentException - * if {@code when.getTime() < 0} or {@code period <= 0}. - * @throws IllegalStateException - * if the {@code Timer} has been canceled, or if the task has been - * scheduled or canceled. - */ - 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); + size = 0; } - /** - * Schedule a task for repeated fixed-rate execution after a specific delay - * has passed. - * - * @param task - * the task to schedule. - * @param delay - * amount of time in milliseconds before first execution. - * @param period - * amount of time in milliseconds between subsequent executions. - * @throws IllegalArgumentException - * if {@code delay < 0} or {@code period <= 0}. - * @throws IllegalStateException - * if the {@code Timer} has been canceled, or if the task has been - * scheduled or canceled. - */ - public void scheduleAtFixedRate(TimerTask task, long delay, long period) { - if (delay < 0 || period <= 0) { - throw new IllegalArgumentException(); + private void fixUp(int k) { + while (k > 1) { + int j = k >> 1; + if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime) + break; + TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; + k = j; } - scheduleImpl(task, delay, period, true); } - /** - * Schedule a task for repeated fixed-rate 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 in milliseconds between subsequent executions. - * @throws IllegalArgumentException - * if {@code when.getTime() < 0} or {@code period <= 0}. - * @throws IllegalStateException - * if the {@code Timer} has been canceled, or if the task has been - * scheduled or canceled. - */ - public void scheduleAtFixedRate(TimerTask task, Date when, long period) { - if (period <= 0 || when.getTime() < 0) { - throw new IllegalArgumentException(); + private void fixDown(int k) { + int j; + while ((j = k << 1) <= size && j > 0) { + if (j < size && + queue[j].nextExecutionTime > queue[j+1].nextExecutionTime) + j++; // j indexes smallest kid + if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime) + break; + TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; + k = j; } - long delay = when.getTime() - System.currentTimeMillis(); - scheduleImpl(task, delay, period, true); } - /* - * Schedule a task. - */ - private void scheduleImpl(TimerTask task, long delay, long period, boolean fixed) { - synchronized (impl) { - if (impl.cancelled) { - throw new IllegalStateException("Timer was canceled"); - } - - long when = delay + System.currentTimeMillis(); - - if (when < 0) { - throw new IllegalArgumentException("Illegal delay to start the TimerTask: " + when); - } - - synchronized (task.lock) { - if (task.isScheduled()) { - throw new IllegalStateException("TimerTask is scheduled already"); - } - - if (task.cancelled) { - throw new IllegalStateException("TimerTask is canceled"); - } - - task.when = when; - task.period = period; - task.fixedRate = fixed; - } - - // insert the newTask into queue - impl.insertTask(task); - } + void heapify() { + for (int i = size/2; i >= 1; i--) + fixDown(i); } } diff --git a/jtransc-rt/src/java/util/TimerTask.java b/jtransc-rt/src/java/util/TimerTask.java index a8ebb429..e53a4203 100644 --- a/jtransc-rt/src/java/util/TimerTask.java +++ b/jtransc-rt/src/java/util/TimerTask.java @@ -1,118 +1,158 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * */ package java.util; /** - * The {@code TimerTask} class represents a task to run at a specified time. The task - * may be run once or repeatedly. + * A task that can be scheduled for one-time or repeated execution by a Timer. * - * @see Timer - * @see Object#wait(long) + * @author Josh Bloch + * @see Timer + * @since 1.3 */ + public abstract class TimerTask implements Runnable { - /* Lock object for synchronization. It's also used by Timer class. */ + /** + * This object is used to control access to the TimerTask internals. + */ final Object lock = new Object(); - /* If timer was cancelled */ - boolean cancelled; - - /* Slots used by Timer */ - long when; + /** + * The state of this task, chosen from the constants below. + */ + int state = VIRGIN; - long period; + /** + * This task has not yet been scheduled. + */ + static final int VIRGIN = 0; - boolean fixedRate; + /** + * This task is scheduled for execution. If it is a non-repeating task, + * it has not yet been executed. + */ + static final int SCHEDULED = 1; - /* - * The time when task will be executed, or the time when task was launched - * if this is task in progress. + /** + * This non-repeating task has already executed (or is currently + * executing) and has not been cancelled. */ - private long scheduledTime; + static final int EXECUTED = 2; - /* - * Method called from the Timer for synchronized getting of when field. + /** + * This task has been cancelled (with a call to TimerTask.cancel). */ - long getWhen() { - synchronized (lock) { - return when; - } - } + static final int CANCELLED = 3; - /* - * Method called from the Timer object when scheduling an event @param time + /** + * Next execution time for this task in the format returned by + * System.currentTimeMillis, assuming this task is scheduled for execution. + * For repeating tasks, this field is updated prior to each task execution. */ - void setScheduledTime(long time) { - synchronized (lock) { - scheduledTime = time; - } - } + long nextExecutionTime; - /* - * Is TimerTask scheduled into any timer? - * - * @return {@code true} if the timer task is scheduled, {@code false} - * otherwise. + /** + * Period in milliseconds for repeating tasks. A positive value indicates + * fixed-rate execution. A negative value indicates fixed-delay execution. + * A value of 0 indicates a non-repeating task. */ - boolean isScheduled() { - synchronized (lock) { - return when > 0 || scheduledTime > 0; - } - } + long period = 0; /** - * Creates a new {@code TimerTask}. + * Creates a new timer task. */ protected TimerTask() { } /** - * Cancels the {@code TimerTask} and removes it from the {@code Timer}'s queue. Generally, it - * returns {@code false} if the call did not prevent a {@code TimerTask} from running at - * least once. Subsequent calls have no effect. + * The action to be performed by this timer task. + */ + public abstract void run(); + + /** + * Cancels this timer task. If the task has been scheduled for one-time + * execution and has not yet run, or has not yet been scheduled, it will + * never run. If the task has been scheduled for repeated execution, it + * will never run again. (If the task is running when this call occurs, + * the task will run to completion, but will never run again.) + * + *

Note that calling this method from within the run method of + * a repeating timer task absolutely guarantees that the timer task will + * not run again. + * + *

This method may be called repeatedly; the second and subsequent + * calls have no effect. * - * @return {@code true} if the call prevented a scheduled execution - * from taking place, {@code false} otherwise. + * @return true if this task is scheduled for one-time execution and has + * not yet run, or this task is scheduled for repeated execution. + * Returns false if the task was scheduled for one-time execution + * and has already run, or if the task was never scheduled, or if + * the task was already cancelled. (Loosely speaking, this method + * returns true if it prevents one or more scheduled + * executions from taking place.) */ public boolean cancel() { - synchronized (lock) { - boolean willRun = !cancelled && when > 0; - cancelled = true; - return willRun; + synchronized(lock) { + boolean result = (state == SCHEDULED); + state = CANCELLED; + return result; } } /** - * Returns the scheduled execution time. If the task execution is in - * progress it returns the execution time of the ongoing task. Tasks which - * have not yet run return an undefined value. + * Returns the scheduled execution time of the most recent + * actual execution of this task. (If this method is invoked + * while task execution is in progress, the return value is the scheduled + * execution time of the ongoing task execution.) * - * @return the most recent execution time. + *

This method is typically invoked from within a task's run method, to + * determine whether the current execution of the task is sufficiently + * timely to warrant performing the scheduled activity: + *

{@code
+     *   public void run() {
+     *       if (System.currentTimeMillis() - scheduledExecutionTime() >=
+     *           MAX_TARDINESS)
+     *               return;  // Too late; skip this execution.
+     *       // Perform the task
+     *   }
+     * }
+ * This method is typically not used in conjunction with + * fixed-delay execution repeating tasks, as their scheduled + * execution times are allowed to drift over time, and so are not terribly + * significant. + * + * @return the time at which the most recent execution of this task was + * scheduled to occur, in the format returned by Date.getTime(). + * The return value is undefined if the task has yet to commence + * its first execution. + * @see Date#getTime() */ public long scheduledExecutionTime() { - synchronized (lock) { - return scheduledTime; + synchronized(lock) { + return (period < 0 ? nextExecutionTime + period + : nextExecutionTime - period); } } - - /** - * The task to run should be specified in the implementation of the {@code run()} - * method. - */ - public abstract void run(); - } diff --git a/jtransc-rt/src/java/util/concurrent/ScheduledThreadPoolExecutor.java b/jtransc-rt/src/java/util/concurrent/ScheduledThreadPoolExecutor.java index 044b9614..0b331a97 100644 --- a/jtransc-rt/src/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/jtransc-rt/src/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -52,19 +52,24 @@ public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialD return f; } + @Override + public void execute(Runnable task) { + timer.schedule(new ScheduledFutureTask(task), 0); + } + @Override public Future submit(Runnable task) { - return schedule(task, 50, TimeUnit.MILLISECONDS); + return schedule(task, 0, TimeUnit.MILLISECONDS); } @Override public Future submit(Runnable task, T result) { - return schedule(Executors.callable(task, result), 50, TimeUnit.MILLISECONDS); + return schedule(Executors.callable(task, result), 0, TimeUnit.MILLISECONDS); } @Override public Future submit(Callable task) { - return schedule(task, 50, TimeUnit.MILLISECONDS); + return schedule(task, 0, TimeUnit.MILLISECONDS); } static private class DelayedWorkQueue extends SynchronousQueue { @@ -113,41 +118,37 @@ public boolean isDone() { @Override public V get() throws InterruptedException, ExecutionException { - if (callable == null) return null; - while (res == null) { - Thread.sleep(100); - } + //if (callable == null) return null; + //while (res == null) { + // Thread.sleep(100); + //} return res; } @Override public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - if (callable == null) return null; - long time = unit.toMillis(timeout); - while (res == null && time > 0) { - time -= 100; - Thread.sleep(100); - } + //if (callable == null) return null; + //long time = unit.toMillis(timeout); + //while (res == null && time > 0) { + // time -= 100; + // Thread.sleep(100); + //} return res; } @Override public void run() { - if (runnable != null) { - execute(runnable); - } + try { + if (runnable != null) { + runnable.run(); + } + + if (callable != null) { + res = callable.call(); + } - if (callable != null) { - execute(new Runnable() { - @Override - public void run() { - try { - res = callable.call(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); + } catch (Exception e) { + e.printStackTrace(); } done = true; } From c9bddb8cf3cab46bdf8d6e4e1c85cf81f9ec13f0 Mon Sep 17 00:00:00 2001 From: Sergey Labutin Date: Wed, 13 Sep 2017 12:16:15 +0300 Subject: [PATCH 2/2] return license in Timer.java --- jtransc-rt/src/java/util/Timer.java | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/jtransc-rt/src/java/util/Timer.java b/jtransc-rt/src/java/util/Timer.java index 91bdd72b..256065ea 100644 --- a/jtransc-rt/src/java/util/Timer.java +++ b/jtransc-rt/src/java/util/Timer.java @@ -1,26 +1,26 @@ /* * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * + * 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 java.util;