@@ -14,7 +14,8 @@ public class DSRuntime {
1414 ///////////////////////////////////////////////////////////////////////////
1515
1616 private static boolean alive = true ;
17- private static long nextCycle = -1 ;
17+ private static long nextCycle = 0 ;
18+ private static boolean hasStarted = false ;
1819 private static RuntimeThread runtimeThread ;
1920 private static Timer timerHead ;
2021 private static Timer timerTail ;
@@ -35,27 +36,30 @@ private DSRuntime() {
3536 * Returns the next time execution is needed.
3637 */
3738 private static void executeTimers () {
38- long now = System .currentTimeMillis ();
39- long nextCycleTmp = now + 60000 ;
39+ long now = System .nanoTime ();
40+ long nextCycleTmp = now + 60000000000l ;
4041 Timer current = null ;
4142 Timer next = null ;
4243 Timer keepHead = null ;
4344 Timer keepTail = null ;
4445 long tmp ;
46+ boolean futureWork ;
4547 //Take the task link list.
4648 synchronized (DSRuntime .class ) {
4749 nextCycle = nextCycleTmp ;
50+ hasStarted = true ;
4851 current = timerHead ;
4952 timerHead = null ;
5053 timerTail = null ;
5154 }
5255 //Execute items (if needed) and retains tasks with future work.
5356 while (alive && (current != null )) {
54- tmp = current .run (now );
57+ futureWork = current .run (now );
5558 next = current .next ;
5659 current .next = null ;
57- if (tmp > 0 ) {
58- if (tmp < nextCycleTmp ) {
60+ if (futureWork ) {
61+ tmp = current .nextRunNanos ();
62+ if (tmp - nextCycleTmp < 0 ) {
5963 nextCycleTmp = tmp ;
6064 }
6165 if (keepHead == null ) {
@@ -70,7 +74,7 @@ private static void executeTimers() {
7074 }
7175 //Add the tasks that have future work back to the main linked list.
7276 synchronized (DSRuntime .class ) {
73- if (nextCycleTmp < nextCycle ) {
77+ if (nextCycleTmp - nextCycle < 0 ) {
7478 nextCycle = nextCycleTmp ;
7579 }
7680 if (keepHead != null ) {
@@ -97,11 +101,27 @@ public static void run(Runnable arg) {
97101 *
98102 * @param arg What to runAt.
99103 * @param start First absolute execution time, or if less or equal to 0, start immediately.
100- * @param interval The millisecond interval at which to run.
104+ * @param intervalMillis The millisecond interval at which to run.
101105 * @return For inspecting and cancel execution.
102106 */
103- public static Timer run (Runnable arg , long start , long interval ) {
104- Timer f = new Timer (arg , start , interval );
107+ public static Timer run (Runnable arg , long start , long intervalMillis ) {
108+ long delayMillis = start - System .currentTimeMillis ();
109+ return runAfterDelay (arg , delayMillis < 0 ? 0 : delayMillis , intervalMillis );
110+ }
111+
112+ /**
113+ * Run periodically starting after the given millisecond delay and repeat at the given millisecond interval.
114+ *
115+ * @param arg What to runAt.
116+ * @param delayMillis The number of millis to wait before first execution.
117+ * @param intervalMillis The millisecond interval at which to run.
118+ * @return For inspecting and cancel execution.
119+ */
120+ public static Timer runAfterDelay (Runnable arg , long delayMillis , long intervalMillis ) {
121+ long intervalNanos = intervalMillis * DSTime .NANOS_IN_MS ;
122+ long delayNanos = delayMillis * DSTime .NANOS_IN_MS ;
123+ long startNanos = System .nanoTime () + delayNanos ;
124+ Timer f = new Timer (arg , startNanos , intervalNanos );
105125 synchronized (DSRuntime .class ) {
106126 if (timerHead == null ) {
107127 timerHead = f ;
@@ -110,8 +130,9 @@ public static Timer run(Runnable arg, long start, long interval) {
110130 timerTail .next = f ;
111131 timerTail = f ;
112132 }
113- if (start < nextCycle ) {
114- nextCycle = start ;
133+ if (!hasStarted || startNanos - nextCycle < 0 ) {
134+ nextCycle = startNanos ;
135+ hasStarted = true ;
115136 DSRuntime .class .notifyAll ();
116137 }
117138 }
@@ -126,7 +147,21 @@ public static Timer run(Runnable arg, long start, long interval) {
126147 * @return For inspecting and cancel execution.
127148 */
128149 public static Timer runAt (Runnable arg , long at ) {
129- Timer f = new Timer (arg , at , -1 );
150+ long delayMillis = at - System .currentTimeMillis ();
151+ return runDelayed (arg , delayMillis < 0 ? 0 : delayMillis );
152+ }
153+
154+ /**
155+ * Run once after the given delay.
156+ *
157+ * @param arg What to runAt.
158+ * @param delayMillis The number of millis to wait before running.
159+ * @return For inspecting and cancel execution.
160+ */
161+ public static Timer runDelayed (Runnable arg , long delayMillis ) {
162+ long delayNanos = delayMillis * DSTime .NANOS_IN_MS ;
163+ long startNanos = System .nanoTime () + delayNanos ;
164+ Timer f = new Timer (arg , startNanos , -1 );
130165 synchronized (DSRuntime .class ) {
131166 if (timerHead == null ) {
132167 timerHead = f ;
@@ -135,25 +170,15 @@ public static Timer runAt(Runnable arg, long at) {
135170 timerTail .next = f ;
136171 timerTail = f ;
137172 }
138- if (at < nextCycle ) {
139- nextCycle = at ;
173+ if (!hasStarted || startNanos - nextCycle < 0 ) {
174+ nextCycle = startNanos ;
175+ hasStarted = true ;
140176 DSRuntime .class .notifyAll ();
141177 }
142178 }
143179 return f ;
144180 }
145181
146- /**
147- * Run once after the given delay.
148- *
149- * @param arg What to runAt.
150- * @param delayMillis The number of millis to wait before running.
151- * @return For inspecting and cancel execution.
152- */
153- public static Timer runDelayed (Runnable arg , long delayMillis ) {
154- return runAt (arg , System .currentTimeMillis () + delayMillis );
155- }
156-
157182 private static void shutdown () {
158183 synchronized (DSRuntime .class ) {
159184 alive = false ;
@@ -173,18 +198,21 @@ public static class Timer implements Runnable {
173198
174199 private long count = 0 ;
175200 private long interval = 0 ;
176- private long lastRun = -1 ;
201+ private long lastRun = 0 ;
202+ boolean hasRun = false ;
177203 private Timer next ; //linked list
178- private long nextRun = 1 ; //0 == canceled, <0 == done
204+ private long nextRun = 0 ;
205+ boolean cancelled = false ;
206+ boolean done = false ;
179207 private Runnable runnable ;
180208 private boolean running = false ;
181209 private boolean skipMissed = true ;
182210
183- Timer (Runnable runnable , long start , long interval ) {
211+ private Timer (Runnable runnable , long start , long interval ) {
184212 this .interval = interval ;
185- if (start <= 0 ) {
186- start = System .currentTimeMillis ();
187- }
213+ // if (start <= 0) {
214+ // start = System.currentTimeMillis();
215+ // }
188216 this .nextRun = start ;
189217 this .runnable = runnable ;
190218 }
@@ -194,30 +222,32 @@ public static class Timer implements Runnable {
194222 * already cancelled.
195223 */
196224 public void cancel () {
197- if (nextRun > 0 ) {
198- nextRun = 0 ;
225+ if (!done ) {
226+ done = true ;
227+ cancelled = true ;
199228 }
200229 }
201230
202- private long computeNextRun (long now ) {
231+ private boolean computeNextRun (long now ) {
203232 if (interval <= 0 ) {
204- return nextRun = -1 ;
233+ done = true ;
234+ return false ;
205235 }
206236 if (skipMissed ) {
207- while (nextRun <= now ) {
237+ while (nextRun - now <= 0 ) {
208238 nextRun += interval ;
209239 }
210240 } else {
211241 nextRun += interval ;
212242 }
213- return nextRun ;
243+ return true ;
214244 }
215245
216246 /**
217247 * The interval between runs, zero or less for no interval.
218248 */
219249 public long getInterval () {
220- return interval ;
250+ return interval / DSTime . NANOS_IN_MS ;
221251 }
222252
223253 /**
@@ -228,14 +258,14 @@ public Runnable getRunnable() {
228258 }
229259
230260 public boolean isCancelled () {
231- return nextRun == 0 ;
261+ return cancelled ;
232262 }
233263
234264 /**
235265 * True if cancelled or was a one time execution and that has finished.
236266 */
237267 public boolean isFinished () {
238- return nextRun <= 0 ;
268+ return done ;
239269 }
240270
241271 /**
@@ -249,7 +279,7 @@ public boolean isRunning() {
249279 * The lastRun run or -1 if it hasn't run yet.
250280 */
251281 public long lastRun () {
252- return lastRun ;
282+ return hasRun ? DSTime . nanoTimeToSystemTimeMillis ( lastRun ) : - 1 ;
253283 }
254284
255285 /**
@@ -258,7 +288,7 @@ public long lastRun() {
258288 * @return 0 or less when finished.
259289 */
260290 public long nextRun () {
261- return nextRun ;
291+ return done ? cancelled ? 0 : - 1 : DSTime . nanoTimeToSystemTimeMillis ( nextRun ) ;
262292 }
263293
264294 /**
@@ -276,27 +306,32 @@ public void run() {
276306 * Executes the task if it is time.
277307 *
278308 * @param now The current time, just an efficiency.
279- * @return The next update time, or 0 or less if done.
309+ * @return Whether the task should be run at some point in the future
280310 */
281- long run (long now ) {
282- if (nextRun <= 0 ) {
283- return nextRun ;
311+ boolean run (long now ) {
312+ if (done ) {
313+ return false ;
284314 }
285- if (now < nextRun ) {
286- return nextRun ;
315+ if (now - nextRun < 0 ) {
316+ return true ;
287317 }
288318 if (running ) {
289319 if (skipMissed ) {
290320 return computeNextRun (now );
291321 }
292- return nextRun ;
322+ return true ;
293323 }
294324 running = true ;
295325 DSRuntime .run (this );
296326 count ++;
297327 lastRun = nextRun ;
328+ hasRun = true ;
298329 return computeNextRun (now );
299330 }
331+
332+ long nextRunNanos () {
333+ return nextRun ;
334+ }
300335
301336 /**
302337 * The number of completed runs.
@@ -319,7 +354,7 @@ public Timer setSkipMissedIntervals(boolean skipMissed) {
319354
320355 public String toString () {
321356 StringBuilder buf = new StringBuilder ();
322- DSTime .encode (nextRun , false , buf );
357+ DSTime .encode (nextRun () , false , buf );
323358 buf .append (" - " ).append (runnable .toString ());
324359 return buf .toString ();
325360 }
@@ -341,7 +376,7 @@ public void run() {
341376 while (alive ) {
342377 executeTimers ();
343378 synchronized (DSRuntime .class ) {
344- delta = nextCycle - System .currentTimeMillis () ;
379+ delta = ( nextCycle - System .nanoTime ()) / DSTime . NANOS_IN_MS ;
345380 if (delta > 0 ) {
346381 try {
347382 DSRuntime .class .wait (delta );
@@ -381,5 +416,4 @@ public void run() {
381416 runtimeThread = new RuntimeThread ();
382417 runtimeThread .start ();
383418 }
384-
385419}
0 commit comments