@@ -14,7 +14,8 @@ public class DSRuntime {
14
14
///////////////////////////////////////////////////////////////////////////
15
15
16
16
private static boolean alive = true ;
17
- private static long nextCycle = -1 ;
17
+ private static long nextCycle = 0 ;
18
+ private static boolean hasStarted = false ;
18
19
private static RuntimeThread runtimeThread ;
19
20
private static Timer timerHead ;
20
21
private static Timer timerTail ;
@@ -35,27 +36,30 @@ private DSRuntime() {
35
36
* Returns the next time execution is needed.
36
37
*/
37
38
private static void executeTimers () {
38
- long now = System .currentTimeMillis ();
39
- long nextCycleTmp = now + 60000 ;
39
+ long now = System .nanoTime ();
40
+ long nextCycleTmp = now + 60000000000l ;
40
41
Timer current = null ;
41
42
Timer next = null ;
42
43
Timer keepHead = null ;
43
44
Timer keepTail = null ;
44
45
long tmp ;
46
+ boolean futureWork ;
45
47
//Take the task link list.
46
48
synchronized (DSRuntime .class ) {
47
49
nextCycle = nextCycleTmp ;
50
+ hasStarted = true ;
48
51
current = timerHead ;
49
52
timerHead = null ;
50
53
timerTail = null ;
51
54
}
52
55
//Execute items (if needed) and retains tasks with future work.
53
56
while (alive && (current != null )) {
54
- tmp = current .run (now );
57
+ futureWork = current .run (now );
55
58
next = current .next ;
56
59
current .next = null ;
57
- if (tmp > 0 ) {
58
- if (tmp < nextCycleTmp ) {
60
+ if (futureWork ) {
61
+ tmp = current .nextRunNanos ();
62
+ if (tmp - nextCycleTmp < 0 ) {
59
63
nextCycleTmp = tmp ;
60
64
}
61
65
if (keepHead == null ) {
@@ -70,7 +74,7 @@ private static void executeTimers() {
70
74
}
71
75
//Add the tasks that have future work back to the main linked list.
72
76
synchronized (DSRuntime .class ) {
73
- if (nextCycleTmp < nextCycle ) {
77
+ if (nextCycleTmp - nextCycle < 0 ) {
74
78
nextCycle = nextCycleTmp ;
75
79
}
76
80
if (keepHead != null ) {
@@ -97,11 +101,27 @@ public static void run(Runnable arg) {
97
101
*
98
102
* @param arg What to runAt.
99
103
* @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.
101
105
* @return For inspecting and cancel execution.
102
106
*/
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 );
105
125
synchronized (DSRuntime .class ) {
106
126
if (timerHead == null ) {
107
127
timerHead = f ;
@@ -110,8 +130,9 @@ public static Timer run(Runnable arg, long start, long interval) {
110
130
timerTail .next = f ;
111
131
timerTail = f ;
112
132
}
113
- if (start < nextCycle ) {
114
- nextCycle = start ;
133
+ if (!hasStarted || startNanos - nextCycle < 0 ) {
134
+ nextCycle = startNanos ;
135
+ hasStarted = true ;
115
136
DSRuntime .class .notifyAll ();
116
137
}
117
138
}
@@ -126,7 +147,21 @@ public static Timer run(Runnable arg, long start, long interval) {
126
147
* @return For inspecting and cancel execution.
127
148
*/
128
149
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 );
130
165
synchronized (DSRuntime .class ) {
131
166
if (timerHead == null ) {
132
167
timerHead = f ;
@@ -135,25 +170,15 @@ public static Timer runAt(Runnable arg, long at) {
135
170
timerTail .next = f ;
136
171
timerTail = f ;
137
172
}
138
- if (at < nextCycle ) {
139
- nextCycle = at ;
173
+ if (!hasStarted || startNanos - nextCycle < 0 ) {
174
+ nextCycle = startNanos ;
175
+ hasStarted = true ;
140
176
DSRuntime .class .notifyAll ();
141
177
}
142
178
}
143
179
return f ;
144
180
}
145
181
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
-
157
182
private static void shutdown () {
158
183
synchronized (DSRuntime .class ) {
159
184
alive = false ;
@@ -173,18 +198,21 @@ public static class Timer implements Runnable {
173
198
174
199
private long count = 0 ;
175
200
private long interval = 0 ;
176
- private long lastRun = -1 ;
201
+ private long lastRun = 0 ;
202
+ boolean hasRun = false ;
177
203
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 ;
179
207
private Runnable runnable ;
180
208
private boolean running = false ;
181
209
private boolean skipMissed = true ;
182
210
183
- Timer (Runnable runnable , long start , long interval ) {
211
+ private Timer (Runnable runnable , long start , long interval ) {
184
212
this .interval = interval ;
185
- if (start <= 0 ) {
186
- start = System .currentTimeMillis ();
187
- }
213
+ // if (start <= 0) {
214
+ // start = System.currentTimeMillis();
215
+ // }
188
216
this .nextRun = start ;
189
217
this .runnable = runnable ;
190
218
}
@@ -194,30 +222,32 @@ public static class Timer implements Runnable {
194
222
* already cancelled.
195
223
*/
196
224
public void cancel () {
197
- if (nextRun > 0 ) {
198
- nextRun = 0 ;
225
+ if (!done ) {
226
+ done = true ;
227
+ cancelled = true ;
199
228
}
200
229
}
201
230
202
- private long computeNextRun (long now ) {
231
+ private boolean computeNextRun (long now ) {
203
232
if (interval <= 0 ) {
204
- return nextRun = -1 ;
233
+ done = true ;
234
+ return false ;
205
235
}
206
236
if (skipMissed ) {
207
- while (nextRun <= now ) {
237
+ while (nextRun - now <= 0 ) {
208
238
nextRun += interval ;
209
239
}
210
240
} else {
211
241
nextRun += interval ;
212
242
}
213
- return nextRun ;
243
+ return true ;
214
244
}
215
245
216
246
/**
217
247
* The interval between runs, zero or less for no interval.
218
248
*/
219
249
public long getInterval () {
220
- return interval ;
250
+ return interval / DSTime . NANOS_IN_MS ;
221
251
}
222
252
223
253
/**
@@ -228,14 +258,14 @@ public Runnable getRunnable() {
228
258
}
229
259
230
260
public boolean isCancelled () {
231
- return nextRun == 0 ;
261
+ return cancelled ;
232
262
}
233
263
234
264
/**
235
265
* True if cancelled or was a one time execution and that has finished.
236
266
*/
237
267
public boolean isFinished () {
238
- return nextRun <= 0 ;
268
+ return done ;
239
269
}
240
270
241
271
/**
@@ -249,7 +279,7 @@ public boolean isRunning() {
249
279
* The lastRun run or -1 if it hasn't run yet.
250
280
*/
251
281
public long lastRun () {
252
- return lastRun ;
282
+ return hasRun ? DSTime . nanoTimeToSystemTimeMillis ( lastRun ) : - 1 ;
253
283
}
254
284
255
285
/**
@@ -258,7 +288,7 @@ public long lastRun() {
258
288
* @return 0 or less when finished.
259
289
*/
260
290
public long nextRun () {
261
- return nextRun ;
291
+ return done ? cancelled ? 0 : - 1 : DSTime . nanoTimeToSystemTimeMillis ( nextRun ) ;
262
292
}
263
293
264
294
/**
@@ -276,27 +306,32 @@ public void run() {
276
306
* Executes the task if it is time.
277
307
*
278
308
* @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
280
310
*/
281
- long run (long now ) {
282
- if (nextRun <= 0 ) {
283
- return nextRun ;
311
+ boolean run (long now ) {
312
+ if (done ) {
313
+ return false ;
284
314
}
285
- if (now < nextRun ) {
286
- return nextRun ;
315
+ if (now - nextRun < 0 ) {
316
+ return true ;
287
317
}
288
318
if (running ) {
289
319
if (skipMissed ) {
290
320
return computeNextRun (now );
291
321
}
292
- return nextRun ;
322
+ return true ;
293
323
}
294
324
running = true ;
295
325
DSRuntime .run (this );
296
326
count ++;
297
327
lastRun = nextRun ;
328
+ hasRun = true ;
298
329
return computeNextRun (now );
299
330
}
331
+
332
+ long nextRunNanos () {
333
+ return nextRun ;
334
+ }
300
335
301
336
/**
302
337
* The number of completed runs.
@@ -319,7 +354,7 @@ public Timer setSkipMissedIntervals(boolean skipMissed) {
319
354
320
355
public String toString () {
321
356
StringBuilder buf = new StringBuilder ();
322
- DSTime .encode (nextRun , false , buf );
357
+ DSTime .encode (nextRun () , false , buf );
323
358
buf .append (" - " ).append (runnable .toString ());
324
359
return buf .toString ();
325
360
}
@@ -341,7 +376,7 @@ public void run() {
341
376
while (alive ) {
342
377
executeTimers ();
343
378
synchronized (DSRuntime .class ) {
344
- delta = nextCycle - System .currentTimeMillis () ;
379
+ delta = ( nextCycle - System .nanoTime ()) / DSTime . NANOS_IN_MS ;
345
380
if (delta > 0 ) {
346
381
try {
347
382
DSRuntime .class .wait (delta );
@@ -381,5 +416,4 @@ public void run() {
381
416
runtimeThread = new RuntimeThread ();
382
417
runtimeThread .start ();
383
418
}
384
-
385
419
}
0 commit comments