1- /*
2- * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
3- *
4- * The MIT License
5- * Copyright © 2014-2022 Ilkka Seppälä
6- *
7- * Permission is hereby granted, free of charge, to any person obtaining a copy
8- * of this software and associated documentation files (the "Software"), to deal
9- * in the Software without restriction, including without limitation the rights
10- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11- * copies of the Software, and to permit persons to whom the Software is
12- * furnished to do so, subject to the following conditions:
13- *
14- * The above copyright notice and this permission notice shall be included in
15- * all copies or substantial portions of the Software.
16- *
17- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23- * THE SOFTWARE.
24- */
251package com .iluwatar .leaderfollowers ;
262
273import java .security .SecureRandom ;
284import java .util .concurrent .Executors ;
295import java .util .concurrent .TimeUnit ;
6+ import lombok .extern .slf4j .Slf4j ;
307
31- /**
32- * Leader/Followers pattern is a concurrency pattern. This pattern behaves like a taxi stand where
33- * one of the threads acts as leader thread which listens for event from event sources,
34- * de-multiplexes, dispatches and handles the event. It promotes the follower to be the new leader.
35- * When processing completes the thread joins the followers queue, if there are no followers then it
36- * becomes the leader and cycle repeats again.
37- *
38- * <p>In this example, one of the workers becomes Leader and listens on the {@link TaskSet} for
39- * work. {@link TaskSet} basically acts as the source of input events for the {@link Worker}, who
40- * are spawned and controlled by the {@link WorkCenter} . When {@link Task} arrives then the leader
41- * takes the work and calls the {@link TaskHandler}. It also calls the {@link WorkCenter} to
42- * promotes one of the followers to be the new leader, who can then process the next work and so on.
43- *
44- * <p>The pros for this pattern are: It enhances CPU cache affinity and eliminates unbound
45- * allocation and data buffer sharing between threads by reading the request into buffer space
46- * allocated on the stack of the leader or by using the Thread-Specific Storage pattern [22] to
47- * allocate memory. It minimizes locking overhead by not exchanging data between threads, thereby
48- * reducing thread synchronization. In bound handle/thread associations, the leader thread
49- * dispatches the event based on the I/O handle. It can minimize priority inversion because no extra
50- * queuing is introduced in the server. It does not require a context switch to handle each event,
51- * reducing the event dispatching latency. Note that promoting a follower thread to fulfill the
52- * leader role requires a context switch. Programming simplicity: The Leader/Followers pattern
53- * simplifies the programming of concurrency models where multiple threads can receive requests,
54- * process responses, and de-multiplex connections using a shared handle set.
55- */
8+ @ Slf4j
569public class App {
5710
58- /** The main method for the leader followers pattern. */
5911 public static void main (String [] args ) throws InterruptedException {
6012 var taskSet = new TaskSet ();
6113 var taskHandler = new TaskHandler ();
@@ -64,18 +16,23 @@ public static void main(String[] args) throws InterruptedException {
6416 execute (workCenter , taskSet );
6517 }
6618
67- /** Start the work, dispatch tasks and stop the thread pool at last. */
6819 private static void execute (WorkCenter workCenter , TaskSet taskSet ) throws InterruptedException {
6920 var workers = workCenter .getWorkers ();
7021 var exec = Executors .newFixedThreadPool (workers .size ());
71- workers .forEach (exec ::submit );
72- Thread .sleep (1000 );
73- addTasks (taskSet );
74- exec .awaitTermination (2 , TimeUnit .SECONDS );
75- exec .shutdownNow ();
22+
23+ try {
24+ workers .forEach (exec ::submit );
25+ Thread .sleep (1000 );
26+ addTasks (taskSet );
27+ boolean terminated = exec .awaitTermination (2 , TimeUnit .SECONDS );
28+ if (!terminated ) {
29+ LOGGER .warn ("Executor did not terminate in the given time." );
30+ }
31+ } finally {
32+ exec .shutdownNow ();
33+ }
7634 }
7735
78- /** Add tasks. */
7936 private static void addTasks (TaskSet taskSet ) throws InterruptedException {
8037 var rand = new SecureRandom ();
8138 for (var i = 0 ; i < 5 ; i ++) {
0 commit comments