779 |
|
assertEquals(effectiveRemovePolicy, |
780 |
|
p.getRemoveOnCancelPolicy()); |
781 |
|
|
782 |
< |
// System.err.println("effectiveDelayedPolicy="+effectiveDelayedPolicy); |
783 |
< |
// System.err.println("effectivePeriodicPolicy="+effectivePeriodicPolicy); |
784 |
< |
// System.err.println("effectiveRemovePolicy="+effectiveRemovePolicy); |
782 |
> |
final boolean periodicTasksContinue = effectivePeriodicPolicy && rnd.nextBoolean(); |
783 |
|
|
784 |
|
// Strategy: Wedge the pool with one wave of "blocker" tasks, |
785 |
< |
// then add a second wave that waits in the queue. |
785 |
> |
// then add a second wave that waits in the queue until unblocked. |
786 |
|
final AtomicInteger ran = new AtomicInteger(0); |
787 |
|
final CountDownLatch poolBlocked = new CountDownLatch(poolSize); |
788 |
|
final CountDownLatch unblock = new CountDownLatch(1); |
789 |
+ |
final RuntimeException exception = new RuntimeException(); |
790 |
|
|
791 |
< |
class Task extends CheckedRunnable { |
792 |
< |
public void realRun() throws InterruptedException { |
793 |
< |
ran.getAndIncrement(); |
794 |
< |
poolBlocked.countDown(); |
795 |
< |
await(unblock); |
791 |
> |
class Task implements Runnable { |
792 |
> |
public void run() { |
793 |
> |
try { |
794 |
> |
ran.getAndIncrement(); |
795 |
> |
poolBlocked.countDown(); |
796 |
> |
await(unblock); |
797 |
> |
} catch (Throwable fail) { threadUnexpectedException(fail); } |
798 |
|
} |
799 |
|
} |
800 |
|
|
801 |
|
class PeriodicTask extends Task { |
802 |
|
PeriodicTask(int rounds) { this.rounds = rounds; } |
803 |
|
int rounds; |
804 |
< |
public void realRun() throws InterruptedException { |
805 |
< |
if (--rounds == 0) super.realRun(); |
804 |
> |
public void run() { |
805 |
> |
if (--rounds == 0) super.run(); |
806 |
> |
// throw exception to surely terminate this periodic task, |
807 |
> |
// but in a separate execution and in a detectable way. |
808 |
> |
if (rounds == -1) throw exception; |
809 |
|
} |
810 |
|
} |
811 |
|
|
880 |
|
|
881 |
|
if (testImplementationDetails) { |
882 |
|
if (effectivePeriodicPolicy) |
879 |
– |
// TODO: ensure periodic tasks continue executing |
883 |
|
periodics.forEach( |
884 |
|
f -> { |
885 |
|
assertFalse(f.isDone()); |
886 |
< |
assertTrue(f.cancel(false)); |
886 |
> |
if (!periodicTasksContinue) |
887 |
> |
assertTrue(f.cancel(false)); |
888 |
|
}); |
889 |
|
else { |
890 |
|
periodics.subList(0, 4).forEach(f -> assertFalse(f.isDone())); |
900 |
|
|
901 |
|
assertTrue(q.isEmpty()); |
902 |
|
|
903 |
+ |
Stream.of(immediates, delayeds, periodics).flatMap(c -> c.stream()) |
904 |
+ |
.forEach(f -> assertTrue(f.isDone())); |
905 |
+ |
|
906 |
|
for (Future<?> f : immediates) assertNull(f.get()); |
907 |
|
|
908 |
|
assertNull(delayeds.get(0).get()); |
911 |
|
else |
912 |
|
assertTrue(delayeds.get(1).isCancelled()); |
913 |
|
|
914 |
< |
periodics.forEach(f -> assertTrue(f.isDone())); |
915 |
< |
periodics.forEach(f -> assertTrue(f.isCancelled())); |
914 |
> |
if (periodicTasksContinue) |
915 |
> |
periodics.forEach( |
916 |
> |
f -> { |
917 |
> |
try { f.get(); } |
918 |
> |
catch (ExecutionException success) { |
919 |
> |
assertSame(exception, success.getCause()); |
920 |
> |
} |
921 |
> |
catch (Throwable fail) { threadUnexpectedException(fail); } |
922 |
> |
}); |
923 |
> |
else |
924 |
> |
periodics.forEach(f -> assertTrue(f.isCancelled())); |
925 |
|
|
926 |
< |
assertEquals(poolSize + 1 + (effectiveDelayedPolicy ? 1 : 0), ran.get()); |
926 |
> |
assertEquals(poolSize + 1 |
927 |
> |
+ (effectiveDelayedPolicy ? 1 : 0) |
928 |
> |
+ (periodicTasksContinue ? 4 : 0), |
929 |
> |
ran.get()); |
930 |
|
} |
931 |
|
|
932 |
|
/** |