GlueGen v2.6.0-rc-20250712
GlueGen, Native Binding Generator for Java™ (public API).
TestWorkerThread01.java
Go to the documentation of this file.
1/**
2 * Copyright 2023 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.common.util;
30
31import java.io.IOException;
32import java.lang.reflect.InvocationTargetException;
33import java.time.Duration;
34import java.time.Instant;
35import java.time.temporal.ChronoUnit;
36import java.util.concurrent.atomic.AtomicInteger;
37
38import org.junit.Assert;
39import org.junit.Test;
40
41import com.jogamp.junit.util.SingletonJunitCase;
42
43import jogamp.common.os.PlatformPropsImpl;
44
45import org.junit.FixMethodOrder;
46import org.junit.runners.MethodSorters;
47
48@FixMethodOrder(MethodSorters.NAME_ASCENDING)
50
51 static class Action implements WorkerThread.Callback {
52 final Duration sleep;
53 final AtomicInteger counter = new AtomicInteger(0);
54 Instant tlast = Instant.now();
55 volatile Duration td = Duration.ZERO;
56
57 Action(final Duration sleep) {
58 this.sleep = sleep;
59 }
60
61 @Override
62 public void run(final WorkerThread self) throws InterruptedException {
63 {
64 java.lang.Thread.sleep(sleep.toMillis());
65 // java.util.concurrent.locks.LockSupport.parkNanos(sleep.toNanos());
66 }
67 final Instant t1 = Instant.now();
68 td = Duration.between(tlast, t1);
69 final int v = counter.incrementAndGet();
70 // System.err.println("action period "+td.toMillis()+"ms, counter "+v+": "+self);
71 tlast = t1;
72 }
73 }
74 static class StateCB implements WorkerThread.StateCallback {
75 final AtomicInteger initCounter = new AtomicInteger(0);
76 final AtomicInteger pausedCounter = new AtomicInteger(0);
77 final AtomicInteger resumedCounter = new AtomicInteger(0);
78 final AtomicInteger endCounter = new AtomicInteger(0);
79
80 @Override
81 public void run(final WorkerThread self, final State cause) throws InterruptedException {
82 // System.err.println("WT-"+cause+": "+self);
83 switch( cause ) {
84 case END:
85 endCounter.incrementAndGet();
86 break;
87 case INIT:
88 initCounter.incrementAndGet();
89 break;
90 case PAUSED:
91 pausedCounter.incrementAndGet();
92 break;
93 case RESUMED:
94 resumedCounter.incrementAndGet();
95 break;
96 default:
97 break;
98 }
99 }
100 }
101
102 static void checkStarted(final WorkerThread wt, final boolean isPaused) {
103 Assert.assertTrue(wt.toString(), wt.isRunning());
104 Assert.assertEquals("isPaused "+isPaused+", "+wt.toString(), !isPaused, wt.isActive());
105 Assert.assertNotNull(wt.toString(), wt.getThread());
106 }
107 static void checkStopped(final WorkerThread wt) {
108 Assert.assertFalse(wt.toString(), wt.isRunning());
109 Assert.assertFalse(wt.toString(), wt.isActive());
110 Assert.assertNull(wt.toString(), wt.getThread());
111 }
112 static void start(final WorkerThread wt, final boolean paused) {
113 // System.err.println("WT Start.0: paused "+paused+", "+wt);
114 wt.start(paused);
115 // System.err.println("WT Start.X: "+wt);
116 }
117 static void stop(final WorkerThread wt, final boolean wait) {
118 // System.err.println("WT Stop.0: wait "+wait+", "+wt);
119 wt.stop(wait);
120 // System.err.println("WT Stop.X: wait "+wait+", "+wt);
121 }
122 static void pause(final WorkerThread wt, final boolean wait) {
123 // System.err.println("WT Pause.0: wait "+wait+", "+wt);
124 wt.pause(wait);
125 // System.err.println("WT Pause.X: wait "+wait+", "+wt);
126 }
127 static void resume(final WorkerThread wt) {
128 // System.err.println("WT Resume.0: "+wt);
129 wt.resume();
130 // System.err.println("WT Resume.X: "+wt);
131 }
132
133 public void testAction(final boolean startPaused, final long periodMS, final long minDelayMS, final long actionMS) throws IOException, InterruptedException, InvocationTargetException {
134 // JDK-8309361: JDK-21 perf-issue: 4ms toleranceMS suffice for JDK < 21, but 20ms for JDK 21
135 // See <https://bugs.openjdk.org/browse/JDK-8309361>
136 final long toleranceMS = PlatformPropsImpl.JAVA_21 ? 20 : 4;
137 final Action action = new Action( 0 < actionMS ? Duration.of(actionMS, ChronoUnit.MILLIS) : Duration.ZERO);
138 final StateCB stateCB = new StateCB();
139 final WorkerThread wt =new WorkerThread(Duration.of(periodMS, ChronoUnit.MILLIS),
140 Duration.of(minDelayMS, ChronoUnit.MILLIS), true /* daemonThread */, action, stateCB);
141
142 final long maxPeriodMS = Math.max(minDelayMS+actionMS, Math.max(periodMS, actionMS));
143 System.err.println("testAction: startPaused "+startPaused+", maxPeriodMS "+maxPeriodMS+", actionMS "+actionMS+", "+wt);
144
145 int counterA = action.counter.get();
146 checkStopped(wt);
147 Assert.assertEquals(0, stateCB.initCounter.get());
148 Assert.assertEquals(0, action.counter.get());
149 Assert.assertEquals(0, stateCB.pausedCounter.get());
150 Assert.assertEquals(0, stateCB.resumedCounter.get());
151 Assert.assertEquals(0, stateCB.endCounter.get());
152 start(wt, startPaused);
153 checkStarted(wt, startPaused /* isPaused */);
154 Assert.assertEquals(1, stateCB.initCounter.get());
155 Assert.assertEquals(startPaused?1:0, stateCB.pausedCounter.get());
156 Assert.assertEquals(startPaused?0:0, stateCB.resumedCounter.get());
157 Assert.assertEquals(0, stateCB.endCounter.get());
158 if( startPaused ) {
159 wt.resume();
160 checkStarted(wt, false /* isPaused */);
161 Assert.assertEquals(1, stateCB.initCounter.get());
162 Assert.assertEquals(1, stateCB.pausedCounter.get());
163 Assert.assertEquals(1, stateCB.resumedCounter.get());
164 Assert.assertEquals(0, stateCB.endCounter.get());
165 }
166 Thread.sleep(maxPeriodMS*3);
167 {
168 final Duration td = action.td;
169 final Duration wt_slept = wt.getSleptDuration();
170 final long actionMS_d = td.minus( wt_slept ).toMillis() - actionMS;
171 System.err.println("actionMS_d "+actionMS_d+" = td "+td.toMillis()+"ms - wt_slept "+wt_slept.toMillis()+"ms - actionMS "+actionMS+"ms < toleranceMS "+toleranceMS+"ms");
172 Assert.assertTrue(Math.abs(actionMS_d) < toleranceMS);
173 }
174
175 checkStarted(wt, false /* isPaused */);
176 stop(wt, true); // running -> stop
177 checkStopped(wt);
178 Assert.assertEquals(1, stateCB.initCounter.get());
179 Assert.assertEquals(startPaused?1:0, stateCB.pausedCounter.get());
180 Assert.assertEquals(startPaused?1:0, stateCB.resumedCounter.get());
181 Assert.assertEquals(1, stateCB.endCounter.get());
182 int counterB = action.counter.get();
183 Assert.assertTrue(counterB > counterA);
184
185 counterA = action.counter.get();
186 checkStopped(wt);
187 start(wt, startPaused); // stop -> running
188 checkStarted(wt, startPaused /* isPaused */);
189 Assert.assertEquals(2, stateCB.initCounter.get());
190 Assert.assertEquals(startPaused?2:0, stateCB.pausedCounter.get());
191 Assert.assertEquals(startPaused?1:0, stateCB.resumedCounter.get());
192 Assert.assertEquals(1, stateCB.endCounter.get());
193 if( startPaused ) {
194 wt.resume();
195 checkStarted(wt, false /* isPaused */);
196 Assert.assertEquals(2, stateCB.initCounter.get());
197 Assert.assertEquals(startPaused?2:0, stateCB.pausedCounter.get());
198 Assert.assertEquals(startPaused?2:0, stateCB.resumedCounter.get());
199 Assert.assertEquals(1, stateCB.endCounter.get());
200 }
201 Thread.sleep(maxPeriodMS*3);
202
203 checkStarted(wt, false /* isPaused */);
204 pause(wt, true /* wait */); // running -> pause
205 checkStarted(wt, true /* isPaused */);
206 Assert.assertEquals(2, stateCB.initCounter.get());
207 Assert.assertEquals(startPaused?3:1, stateCB.pausedCounter.get());
208 Assert.assertEquals(startPaused?2:0, stateCB.resumedCounter.get());
209 Assert.assertEquals(1, stateCB.endCounter.get());
210 counterB = action.counter.get();
211 Assert.assertTrue(counterB > counterA);
212
213 Thread.sleep(maxPeriodMS);
214 counterA = action.counter.get();
215 Assert.assertTrue(counterB == counterA);
216 resume(wt); // pause -> running
217 checkStarted(wt, false /* isPaused */);
218 Assert.assertEquals(2, stateCB.initCounter.get());
219 Assert.assertEquals(startPaused?3:1, stateCB.pausedCounter.get());
220 Assert.assertEquals(startPaused?3:1, stateCB.resumedCounter.get());
221 Assert.assertEquals(1, stateCB.endCounter.get());
222 Thread.sleep(maxPeriodMS*3);
223
224 checkStarted(wt, false /* isPaused */);
225 pause(wt, true /* wait */); // running -> pause
226 checkStarted(wt, true /* isPaused */);
227 Assert.assertEquals(2, stateCB.initCounter.get());
228 Assert.assertEquals(startPaused?4:2, stateCB.pausedCounter.get());
229 Assert.assertEquals(startPaused?3:1, stateCB.resumedCounter.get());
230 Assert.assertEquals(1, stateCB.endCounter.get());
231 counterB = action.counter.get();
232 Assert.assertTrue(counterB > counterA);
233 counterA = counterB;
234
235 checkStarted(wt, true /* isPaused */);
236 stop(wt, true); // pause -> stop
237 checkStopped(wt);
238 Assert.assertEquals(2, stateCB.initCounter.get());
239 Assert.assertEquals(startPaused?4:2, stateCB.pausedCounter.get());
240 Assert.assertEquals(startPaused?4:2, stateCB.resumedCounter.get());
241 Assert.assertEquals(2, stateCB.endCounter.get());
242 counterB = action.counter.get();
243 Assert.assertTrue(counterB == counterA);
244
245 resume(wt); // stop -> stop
246 checkStopped(wt);
247 Assert.assertEquals(2, stateCB.initCounter.get());
248 Assert.assertEquals(startPaused?4:2, stateCB.pausedCounter.get());
249 Assert.assertEquals(startPaused?4:2, stateCB.resumedCounter.get());
250 Assert.assertEquals(2, stateCB.endCounter.get());
251
252 pause(wt, true /* wait */); // stop -> stop
253 checkStopped(wt);
254 Assert.assertEquals(2, stateCB.initCounter.get());
255 Assert.assertEquals(startPaused?4:2, stateCB.pausedCounter.get());
256 Assert.assertEquals(startPaused?4:2, stateCB.resumedCounter.get());
257 Assert.assertEquals(2, stateCB.endCounter.get());
258 }
259
260 @Test
261 public void test01ZeroAction() throws IOException, InterruptedException, InvocationTargetException {
262 testAction(false, 16 /* periodMS */, 0 /* minDelayMS */, 0 /* actionMS*/);
263 testAction(true, 16 /* periodMS */, 0 /* minDelayMS */, 0 /* actionMS*/);
264 }
265
266 @Test
267 public void test02MidAction() throws IOException, InterruptedException, InvocationTargetException {
268 testAction(false, 16 /* periodMS */, 0 /* minDelayMS */, 8 /* actionMS*/);
269 testAction(true, 16 /* periodMS */, 0 /* minDelayMS */, 8 /* actionMS*/);
270 }
271
272 @Test
273 public void test03HeavyAction() throws IOException, InterruptedException, InvocationTargetException {
274 testAction(false, 16 /* periodMS */, 0 /* minDelayMS */, 20 /* actionMS*/);
275 testAction(true, 16 /* periodMS */, 0 /* minDelayMS */, 20 /* actionMS*/);
276 }
277
278 @Test
279 public void test03ZeroMidAction() throws IOException, InterruptedException, InvocationTargetException {
280 testAction(false, 0 /* periodMS */, 0 /* minDelayMS */, 8 /* actionMS*/);
281 testAction(true, 0 /* periodMS */, 0 /* minDelayMS */, 8 /* actionMS*/);
282 }
283
284 @Test
285 public void test04ZeroMinDelayMidAction() throws IOException, InterruptedException, InvocationTargetException {
286 testAction(false, 0 /* periodMS */, 4 /* minDelayMS */, 8 /* actionMS*/);
287 testAction(true, 0 /* periodMS */, 4 /* minDelayMS */, 8 /* actionMS*/);
288 }
289
290 @Test
291 public void test05MinDelayMidAction() throws IOException, InterruptedException, InvocationTargetException {
292 testAction(false, 8 /* periodMS */, 8 /* minDelayMS */, 8 /* actionMS*/);
293 testAction(true, 8 /* periodMS */, 8 /* minDelayMS */, 8 /* actionMS*/);
294 }
295
296 @Test
297 public void test10InitEnd01() throws IOException, InterruptedException, InvocationTargetException {
298 // Issuing stop not in the worker-thread
299 final AtomicInteger actionLatch = new AtomicInteger(0);
300 final WorkerThread.Callback action = (final WorkerThread self) -> {
301 java.lang.Thread.sleep(1);
302 final boolean v = actionLatch.compareAndSet(0, 1);
303 // System.err.println("action set "+v+": "+self);
304 };
305 final StateCB stateCB = new StateCB();
306
307 Assert.assertEquals(0, stateCB.initCounter.get());
308 Assert.assertEquals(0, actionLatch.get());
309 Assert.assertEquals(0, stateCB.pausedCounter.get());
310 Assert.assertEquals(0, stateCB.resumedCounter.get());
311 Assert.assertEquals(0, stateCB.endCounter.get());
312
313 final long minPeriodMS = 2;
314 final long maxPeriodMS = 4;
315 final WorkerThread wt =new WorkerThread(Duration.of(minPeriodMS, ChronoUnit.MILLIS),
316 Duration.of(0, ChronoUnit.MILLIS), true /* daemonThread */,
317 action, stateCB);
318 Assert.assertEquals(0, stateCB.initCounter.get());
319 Assert.assertEquals(0, actionLatch.get());
320 Assert.assertEquals(0, stateCB.pausedCounter.get());
321 Assert.assertEquals(0, stateCB.resumedCounter.get());
322 Assert.assertEquals(0, stateCB.endCounter.get());
323 checkStopped(wt);
324
325 start(wt, true);
326 checkStarted(wt, true /* isPaused */);
327 Assert.assertEquals(1, stateCB.initCounter.get());
328 Assert.assertEquals(0, actionLatch.get());
329 Assert.assertEquals(1, stateCB.pausedCounter.get());
330 Assert.assertEquals(0, stateCB.resumedCounter.get());
331 Assert.assertEquals(0, stateCB.endCounter.get());
332
333 wt.resume();
334 checkStarted(wt, false /* isPaused */);
335 Assert.assertEquals(1, stateCB.initCounter.get());
336 // maybe: Assert.assertEquals(1, actionLatch.get());
337 Assert.assertEquals(1, stateCB.pausedCounter.get());
338 Assert.assertEquals(1, stateCB.resumedCounter.get());
339 Assert.assertEquals(0, stateCB.endCounter.get());
340
341 Thread.sleep(maxPeriodMS);
342 Assert.assertEquals(1, stateCB.initCounter.get());
343 Assert.assertEquals(1, actionLatch.get());
344 Assert.assertEquals(1, stateCB.pausedCounter.get());
345 Assert.assertEquals(1, stateCB.resumedCounter.get());
346 Assert.assertEquals(0, stateCB.endCounter.get());
347
348 checkStarted(wt, false /* isPaused */);
349 stop(wt, true);
350 checkStopped(wt);
351 Assert.assertEquals(1, stateCB.initCounter.get());
352 Assert.assertEquals(1, actionLatch.get());
353 Assert.assertEquals(1, stateCB.pausedCounter.get());
354 Assert.assertEquals(1, stateCB.resumedCounter.get());
355 Assert.assertEquals(1, stateCB.endCounter.get());
356
357 actionLatch.set(0);
358 Assert.assertEquals(0, actionLatch.get());
359 start(wt, false);
360 checkStarted(wt, false/* isPaused */);
361 Assert.assertEquals(2, stateCB.initCounter.get());
362 // maybe: Assert.assertEquals(1, actionLatch.get());
363 Assert.assertEquals(1, stateCB.pausedCounter.get());
364 Assert.assertEquals(1, stateCB.resumedCounter.get());
365 Assert.assertEquals(1, stateCB.endCounter.get());
366
367 Thread.sleep(maxPeriodMS);
368 Assert.assertEquals(2, stateCB.initCounter.get());
369 Assert.assertEquals(1, actionLatch.get());
370 Assert.assertEquals(1, stateCB.pausedCounter.get());
371 Assert.assertEquals(1, stateCB.resumedCounter.get());
372 Assert.assertEquals(1, stateCB.endCounter.get());
373
374 checkStarted(wt, false /* isPaused */);
375 stop(wt, true);
376 checkStopped(wt);
377 Assert.assertEquals(2, stateCB.initCounter.get());
378 Assert.assertEquals(1, actionLatch.get());
379 Assert.assertEquals(1, stateCB.pausedCounter.get());
380 Assert.assertEquals(1, stateCB.resumedCounter.get());
381 Assert.assertEquals(2, stateCB.endCounter.get());
382 }
383
384 @Test
385 public void test11InitEnd02() throws IOException, InterruptedException, InvocationTargetException {
386 // Issuing stop on the worker-thread
387 final AtomicInteger actionCounter = new AtomicInteger(0);
388 final WorkerThread.Callback action = (final WorkerThread self) -> {
389 java.lang.Thread.sleep(1);
390 final int v = actionCounter.incrementAndGet();
391 // System.err.println("action cntr "+v+": "+self);
392 if( 8 == v ) {
393 stop(self, true);
394 }
395 };
396 final StateCB stateCB = new StateCB();
397
398 Assert.assertEquals(0, stateCB.initCounter.get());
399 Assert.assertEquals(0, actionCounter.get());
400 Assert.assertEquals(0, stateCB.pausedCounter.get());
401 Assert.assertEquals(0, stateCB.resumedCounter.get());
402 Assert.assertEquals(0, stateCB.endCounter.get());
403
404 // JDK-8309361: JDK-21 perf-issue: 16ms maxPeriodMS suffice for JDK < 21, but 40ms for JDK 21
405 // See <https://bugs.openjdk.org/browse/JDK-8309361>
406 final long minPeriodMS = 2;
407 final long maxPeriodMS = PlatformPropsImpl.JAVA_21 ? 40 : 16;
408
409 final WorkerThread wt =new WorkerThread(Duration.of(minPeriodMS, ChronoUnit.MILLIS),
410 Duration.of(0, ChronoUnit.MILLIS), true /* daemonThread */,
411 action, stateCB);
412 Assert.assertEquals(0, stateCB.initCounter.get());
413 Assert.assertEquals(0, actionCounter.get());
414 Assert.assertEquals(0, stateCB.pausedCounter.get());
415 Assert.assertEquals(0, stateCB.resumedCounter.get());
416 Assert.assertEquals(0, stateCB.endCounter.get());
417 checkStopped(wt);
418
419 start(wt, true);
420 checkStarted(wt, true /* isPaused */);
421 Assert.assertEquals(1, stateCB.initCounter.get());
422 Assert.assertEquals(0, actionCounter.get());
423 Assert.assertEquals(1, stateCB.pausedCounter.get());
424 Assert.assertEquals(0, stateCB.resumedCounter.get());
425 Assert.assertEquals(0, stateCB.endCounter.get());
426
427 wt.resume();
428 checkStarted(wt, false /* isPaused */);
429 Assert.assertEquals(1, stateCB.initCounter.get());
430 // maybe Assert.assertEquals(1, actionCounter.get());
431 Assert.assertEquals(1, stateCB.pausedCounter.get());
432 Assert.assertEquals(1, stateCB.resumedCounter.get());
433 Assert.assertEquals(0, stateCB.endCounter.get());
434
435 Thread.sleep(maxPeriodMS);
436 Assert.assertEquals(1, stateCB.initCounter.get());
437 Assert.assertTrue(0 < actionCounter.get());
438 Assert.assertEquals(1, stateCB.pausedCounter.get());
439 Assert.assertEquals(1, stateCB.resumedCounter.get());
440 Assert.assertEquals(1, stateCB.endCounter.get());
441 checkStopped(wt);
442
443 actionCounter.set(0);
444 Assert.assertEquals(0, actionCounter.get());
445 start(wt, false);
446 checkStarted(wt, false/* isPaused */);
447 Assert.assertEquals(2, stateCB.initCounter.get());
448 // maybe: Assert.assertEquals(1, actionLatch.get());
449 Assert.assertEquals(1, stateCB.pausedCounter.get());
450 Assert.assertEquals(1, stateCB.resumedCounter.get());
451 Assert.assertEquals(1, stateCB.endCounter.get());
452
453 Thread.sleep(maxPeriodMS);
454 Assert.assertEquals(2, stateCB.initCounter.get());
455 Assert.assertTrue(0 < actionCounter.get());
456 Assert.assertEquals(1, stateCB.pausedCounter.get());
457 Assert.assertEquals(1, stateCB.resumedCounter.get());
458 Assert.assertEquals(2, stateCB.endCounter.get());
459 checkStopped(wt);
460 }
461
462 @Test
463 public void test20ExceptionAtWork() throws IOException, InterruptedException, InvocationTargetException {
464 final AtomicInteger actionCounter = new AtomicInteger(0);
465 final WorkerThread.Callback action = (final WorkerThread self) -> {
466 java.lang.Thread.sleep(1);
467 final int v = actionCounter.incrementAndGet();
468 // System.err.println("action cntr "+v+": "+self);
469 if( 8 == v ) {
470 throw new RuntimeException("Test exception from worker action: "+self);
471 }
472 };
473 final StateCB stateCB = new StateCB();
474
475 Assert.assertEquals(0, stateCB.initCounter.get());
476 Assert.assertEquals(0, actionCounter.get());
477 Assert.assertEquals(0, stateCB.pausedCounter.get());
478 Assert.assertEquals(0, stateCB.resumedCounter.get());
479 Assert.assertEquals(0, stateCB.endCounter.get());
480
481 // JDK-8309361: JDK-21 perf-issue: 16ms maxPeriodMS suffice for JDK < 21, but 40ms for JDK 21
482 // See <https://bugs.openjdk.org/browse/JDK-8309361>
483 final long minPeriodMS = 2;
484 final long maxPeriodMS = PlatformPropsImpl.JAVA_21 ? 40 : 16;
485
486 final WorkerThread wt =new WorkerThread(Duration.of(minPeriodMS, ChronoUnit.MILLIS),
487 Duration.of(0, ChronoUnit.MILLIS), true /* daemonThread */,
488 action, stateCB);
489 Assert.assertEquals(0, stateCB.initCounter.get());
490 Assert.assertEquals(0, actionCounter.get());
491 Assert.assertEquals(0, stateCB.pausedCounter.get());
492 Assert.assertEquals(0, stateCB.resumedCounter.get());
493 Assert.assertEquals(0, stateCB.endCounter.get());
494 checkStopped(wt);
495
496 start(wt, true);
497 checkStarted(wt, true /* isPaused */);
498 Assert.assertEquals(1, stateCB.initCounter.get());
499 Assert.assertEquals(0, actionCounter.get());
500 Assert.assertEquals(1, stateCB.pausedCounter.get());
501 Assert.assertEquals(0, stateCB.resumedCounter.get());
502 Assert.assertEquals(0, stateCB.endCounter.get());
503
504 wt.resume();
505 checkStarted(wt, false /* isPaused */);
506 Assert.assertEquals(1, stateCB.initCounter.get());
507 // maybe: Assert.assertEquals(1, actionLatch.get());
508 Assert.assertEquals(1, stateCB.pausedCounter.get());
509 Assert.assertEquals(1, stateCB.resumedCounter.get());
510 Assert.assertEquals(0, stateCB.endCounter.get());
511
512 Thread.sleep(maxPeriodMS);
513 Assert.assertEquals(1, stateCB.initCounter.get());
514 Assert.assertTrue(0 < actionCounter.get());
515 Assert.assertEquals(2, stateCB.pausedCounter.get());
516 Assert.assertEquals(1, stateCB.resumedCounter.get());
517 Assert.assertEquals(0, stateCB.endCounter.get());
518 checkStarted(wt, true /* isPaused */);
519 Assert.assertTrue(wt.hasError());
520 Assert.assertNotNull(wt.getError(true));
521 final int counterA = actionCounter.get();
522
523 wt.resume();
524 checkStarted(wt, false /* isPaused */);
525 Assert.assertEquals(1, stateCB.initCounter.get());
526 Assert.assertTrue(0 < actionCounter.get());
527 Assert.assertEquals(2, stateCB.pausedCounter.get());
528 Assert.assertEquals(2, stateCB.resumedCounter.get());
529 Assert.assertEquals(0, stateCB.endCounter.get());
530 Thread.sleep(maxPeriodMS);
531
532 stop(wt, true);
533 checkStopped(wt);
534 final int counterB = actionCounter.get();
535 Assert.assertTrue(counterB > counterA);
536 Assert.assertEquals(1, stateCB.initCounter.get());
537 Assert.assertTrue(0 < actionCounter.get());
538 Assert.assertEquals(2, stateCB.pausedCounter.get());
539 Assert.assertEquals(2, stateCB.resumedCounter.get());
540 Assert.assertEquals(1, stateCB.endCounter.get());
541 }
542
543 public static void main(final String args[]) throws IOException {
544 final String tstname = TestWorkerThread01.class.getName();
545 org.junit.runner.JUnitCore.main(tstname);
546 }
547
548}
void testAction(final boolean startPaused, final long periodMS, final long minDelayMS, final long actionMS)
static void main(final String args[])
A re-start()'able, pause(boolean)'able and interrupt'able worker thread with an optional minimum exec...
final boolean hasError()
Returns true if an exception occured during Callable work execution.
final synchronized void start(final boolean paused)
Starts execution of a new worker thread if not isRunning, i.e.
final Exception getError(final boolean clear)
Returns the exception is hasError().
final synchronized void pause(final boolean waitUntilDone)
Pauses execution of the start()'ed worker thread.
final synchronized void resume()
Resumes execution of the pause(boolean)'ed worker thread.
final synchronized void stop(final boolean waitUntilDone)
Stops execution of the start()'ed worker thread.
final Thread getThread()
Returns the worker thread if isRunning(), otherwise null.
final boolean isRunning()
Returns true if the worker thread has started via start() and has not ended, e.g.
final Duration getSleptDuration()
Returns the slept Duration delta of getMinPeriod() and consumed Callback#run() duration,...
final boolean isActive()
Returns true if the worker thread isRunning() and is not paused.