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:
@@ -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
|
||||
Reference in New Issue
Block a user