executors: ExecutorService lifecycle companion code

Adds the executors module: shutdown() vs shutdownNow(), the graceful
two-phase shutdown pattern, AutoCloseable/try-with-resources (JDK 19+),
newVirtualThreadPerTaskExecutor() timing vs a bounded pool, and the
submit()-without-get() lost-exception trap. 5 runnable demos, 1 JUnit
correctness test class (23 tests), 6 captured output transcripts.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FhzLY5p6okFva3qsnsRyvM
This commit is contained in:
2026-09-30 06:54:17 +00:00
co-authored by Claude Sonnet 5
parent 55ee850a75
commit bc5153d2a5
17 changed files with 607 additions and 0 deletions
@@ -0,0 +1,24 @@
=== shutdown(): lets running AND already-queued tasks finish ===
task-0: started
task-1: started
main: called shutdown() - isShutdown=true, isTerminated=false
task-0: finished normally
task-2: started
task-1: finished normally
task-3: started
task-3: finished normally
task-4: started
task-2: finished normally
task-5: started
task-4: finished normally
task-5: finished normally
main: awaitTermination returned true - all 6 tasks ran to completion, none were skipped
=== shutdownNow(): interrupts running tasks, abandons queued ones ===
task-0: started
task-1: started
main: called shutdownNow() - 4 queued tasks abandoned, never started
task-1: interrupted, exiting early
task-0: interrupted, exiting early
main: awaitTermination returned true - the 2 running tasks were interrupted mid-sleep, not allowed to finish
done
@@ -0,0 +1,13 @@
=== Case 1: tasks finish comfortably inside the grace period ===
quickPool: shutdown() called, waiting up to 1s for a clean finish
quick-task-1: done (200ms)
quick-task-0: done (200ms)
quickPool: terminated cleanly within the grace period
=== Case 2: a task outlives the grace period, forcing shutdownNow() ===
slowPool: shutdown() called, waiting up to 1s for a clean finish
slow-task: started, will try to sleep 3s
slowPool: grace period expired, escalating to shutdownNow()
slow-task: interrupted during shutdownNow(), stopping early
slowPool: terminated after shutdownNow()
done
@@ -0,0 +1,7 @@
=== try-with-resources: close() runs the graceful pattern automatically ===
main: leaving the try-with-resources block now
task-2: finished
task-0: finished
task-1: finished
main: back from the try-with-resources block - the pool is terminated, every task already finished, no separate awaitTermination() call was written
done
@@ -0,0 +1,10 @@
Running 5000 tasks that each sleep 50ms.
sample task thread: VirtualThread[#22]/runnable@ForkJoinPool-1-worker-1
newVirtualThreadPerTaskExecutor(): 5000/5000 tasks completed in 121ms
(121ms is close to the 50ms a single task takes - every task ran concurrently, nothing waited for a free worker)
sample task thread: Thread[#5027,pool-1-thread-1,5,main]
newFixedThreadPool(20): 5000/5000 tasks completed in 12556ms
(12556ms is roughly 250 rounds of 50ms each - only 20 tasks are ever running at once)
done
@@ -0,0 +1,13 @@
=== execute(): uncaught exception reaches the default handler, gets printed ===
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: boom from execute()
at com.ankurm.executors.LostExceptionTrapDemo.lambda$main$0(LostExceptionTrapDemo.java:22)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
at java.base/java.lang.Thread.run(Thread.java:1474)
=== submit(): same exception, but nobody calls get() - dead silence ===
main: task's Future exists (isDone=true), but its exception was never printed anywhere - it's just sitting inside the Future
=== submit() + get(): the SAME exception, now surfaced by calling get() ===
main: caught ExecutionException, cause = java.lang.RuntimeException: boom from submit(), retrieved via get()
done
@@ -0,0 +1,4 @@
-------------------------------------------------------------------------------
Test set: com.ankurm.executors.ExecutorShutdownBehaviorTest
-------------------------------------------------------------------------------
Tests run: 23, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.417 s -- in com.ankurm.executors.ExecutorShutdownBehaviorTest