Skip to content

Commit cbc7650

Browse files
committed
feat: convert CyclicBarrier subsystem startup demo to use ExecutorService with graceful shutdown
WHAT was added: - MainWithExecutorService demonstrating subsystem startup coordination using: - CyclicBarrier to synchronize four subsystems (Web Server, Database, Cache, Messaging Service). - ExecutorService with a fixed thread pool sized to numberOfSubsystems to manage worker threads. - Subsystem Runnable that: - Simulates initialization via Thread.sleep(initializationTimeMillis). - Calls barrier.await() after initialization so all subsystems wait at the barrier. - Logs lifecycle events: starting, initialization complete, waiting at barrier, and proceeding after barrier. - Main performs orderly shutdown: - executor.shutdown() followed by awaitTermination with a timeout. - Forceful shutdown via shutdownNow() if tasks do not finish in time. - Proper interrupt handling in the shutdown path. WHY this matters: - Shows a production-friendly pattern that combines high-level concurrency utilities: - ExecutorService handles thread lifecycle and pooling for resource efficiency. - CyclicBarrier ensures all subsystems reach the same readiness checkpoint before continuing. - Demonstrates robust program termination and resource cleanup, which is essential in real systems. - Practical for real-world cases such as orchestrating microservice initialization, multi-component startup, and phased pipelines. HOW it works: 1. Create CyclicBarrier with party count equal to numberOfSubsystems and a barrier action that prints a completion message. 2. Create a fixed thread pool ExecutorService and submit one Subsystem task per component. 3. Each Subsystem sleeps to simulate startup work, then calls barrier.await(). When the last party arrives: - Barrier action runs. - All participant threads are released concurrently to proceed. 4. Main calls executor.shutdown() and waits up to 10 seconds for termination. - If threads fail to terminate, main triggers executor.shutdownNow() to interrupt remaining tasks and logs forcing shutdown. 5. Subsystem code handles InterruptedException by restoring interrupt status and BrokenBarrierException by logging an error. NOTES, GOTCHAS, and RECOMMENDATIONS: - Use awaitTermination with a reasonable timeout to avoid indefinite blocking in main. - Always handle BrokenBarrierException in tasks; it can occur if another thread is interrupted or the barrier is reset. - If subsystem initialization is long-running or can hang, prefer shutdownNow() plus cooperative interruption in the task logic. - For many short tasks or dynamic workloads, consider ForkJoinPool or work-stealing to improve throughput and load balancing. - If barrier action performs heavy work, run that action in a separate thread or keep it lightweight to avoid delaying participants. - For multi-phase synchronization, reuse CyclicBarrier across phases, or create one barrier per phase depending on complexity. PERF and HARDWARE CONSIDERATIONS: - Thread count should generally match available hardware threads for CPU bound tasks. For IO-bound initialization, a larger pool may be acceptable. - On NUMA systems, consider data and thread affinity for improved cache locality when initialization touches large shared state. SHORT KEY: cyclicbarrier executorservice subsystem startup graceful-shutdown barrier-action. Signed-off-by: https://github.com/Someshdiwan <[email protected]>
1 parent 9d4387e commit cbc7650

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import java.util.concurrent.*;
2+
3+
/**
4+
* ExecutorService version of the CyclicBarrier subsystem startup example.
5+
*/
6+
public class MainWithExecutorService {
7+
public static void main(String[] args) {
8+
int numberOfSubsystems = 4;
9+
10+
// Barrier action: runs once when all subsystems reach the barrier
11+
CyclicBarrier barrier = new CyclicBarrier(numberOfSubsystems, () ->
12+
System.out.println("All subsystems are up and running. System startup complete.")
13+
);
14+
15+
// Use a fixed thread pool to manage threads
16+
ExecutorService executor = Executors.newFixedThreadPool(numberOfSubsystems);
17+
18+
// Submit subsystem tasks to the executor
19+
executor.submit(new Subsystem("Web Server", 2000, barrier));
20+
executor.submit(new Subsystem("Database", 4000, barrier));
21+
executor.submit(new Subsystem("Cache", 3000, barrier));
22+
executor.submit(new Subsystem("Messaging Service", 3500, barrier));
23+
24+
// orderly shutdown and wait for completion
25+
executor.shutdown();
26+
try {
27+
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
28+
System.out.println("Forcing shutdown...");
29+
executor.shutdownNow();
30+
}
31+
} catch (InterruptedException e) {
32+
executor.shutdownNow();
33+
Thread.currentThread().interrupt();
34+
}
35+
36+
System.out.println("Main finished.");
37+
}
38+
}
39+
40+
class Subsystem implements Runnable {
41+
private final String name;
42+
private final int initializationTimeMillis;
43+
private final CyclicBarrier barrier;
44+
45+
public Subsystem(String name, int initializationTimeMillis, CyclicBarrier barrier) {
46+
this.name = name;
47+
this.initializationTimeMillis = initializationTimeMillis;
48+
this.barrier = barrier;
49+
}
50+
51+
@Override
52+
public void run() {
53+
try {
54+
System.out.println(name + " starting initialization...");
55+
Thread.sleep(initializationTimeMillis); // simulate initialization work
56+
System.out.println(name + " initialization complete. Waiting at barrier...");
57+
barrier.await(); // wait for other subsystems
58+
System.out.println(name + " proceeding after barrier.");
59+
} catch (InterruptedException e) {
60+
Thread.currentThread().interrupt();
61+
System.err.println(name + " was interrupted.");
62+
} catch (BrokenBarrierException e) {
63+
System.err.println(name + " barrier broken: " + e.getMessage());
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)