11/*
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).
2+ * This project is licensed under the MIT license.
3+ * Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
34 *
45 * The MIT License
56 * Copyright © 2014-2022 Ilkka Seppälä
1617 *
1718 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1819 * 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
20+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2122 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2223 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2324 * THE SOFTWARE.
2829import java .util .concurrent .ConcurrentLinkedQueue ;
2930import lombok .extern .slf4j .Slf4j ;
3031
31- /** Abstract class of all the instance implementation classes. */
32+ /**
33+ * Abstract base class for all instance implementations in the leader election system.
34+ *
35+ * Each instance runs on its own thread and processes incoming messages asynchronously.
36+ * This version fixes the busy loop problem by adding a short sleep when no messages are present.
37+ */
3238@ Slf4j
3339public abstract class AbstractInstance implements Instance , Runnable {
3440
41+ // Interval between heartbeats in milliseconds.
3542 protected static final int HEARTBEAT_INTERVAL = 5000 ;
3643 private static final String INSTANCE = "Instance " ;
3744
@@ -41,7 +48,13 @@ public abstract class AbstractInstance implements Instance, Runnable {
4148 protected int leaderId ;
4249 protected boolean alive ;
4350
44- /** Constructor of BullyInstance. */
51+ /**
52+ * Constructor initializing the instance.
53+ *
54+ * @param messageManager manager to send/receive messages
55+ * @param localId ID of this instance
56+ * @param leaderId current leader ID
57+ */
4558 public AbstractInstance (MessageManager messageManager , int localId , int leaderId ) {
4659 this .messageManager = messageManager ;
4760 this .messageQueue = new ConcurrentLinkedQueue <>();
@@ -50,20 +63,31 @@ public AbstractInstance(MessageManager messageManager, int localId, int leaderId
5063 this .alive = true ;
5164 }
5265
53- /** The instance will execute the message in its message queue periodically once it is alive. */
66+ /**
67+ * Thread run loop — continuously processes messages while instance is alive.
68+ *
69+ * 🟢 FIXED: Added small sleep when queue is empty to avoid busy looping.
70+ */
5471 @ Override
55- @ SuppressWarnings ("squid:S2189" )
5672 public void run () {
57- while (true ) {
73+ while (alive ) {
5874 if (!this .messageQueue .isEmpty ()) {
59- this .processMessage (this .messageQueue .remove ());
75+ processMessage (this .messageQueue .poll ());
76+ } else {
77+ try {
78+ Thread .sleep (100 ); // 🔸 Prevents busy loop CPU overuse
79+ } catch (InterruptedException e ) {
80+ Thread .currentThread ().interrupt ();
81+ LOGGER .warn (INSTANCE + localId + " thread interrupted." );
82+ break ;
83+ }
6084 }
6185 }
86+ LOGGER .info (INSTANCE + localId + " stopped running." );
6287 }
6388
6489 /**
65- * Once messages are sent to the certain instance, it will firstly be added to the queue and wait
66- * to be executed.
90+ * Add a new message to the queue to be processed.
6791 *
6892 * @param message Message sent by other instances
6993 */
@@ -72,74 +96,58 @@ public void onMessage(Message message) {
7296 messageQueue .offer (message );
7397 }
7498
75- /**
76- * Check if the instance is alive or not.
77- *
78- * @return {@code true} if the instance is alive.
79- */
99+ /** Check if this instance is alive. */
80100 @ Override
81101 public boolean isAlive () {
82102 return alive ;
83103 }
84104
85- /**
86- * Set the health status of the certain instance.
87- *
88- * @param alive {@code true} for alive.
89- */
105+ /** Update the alive status of this instance. */
90106 @ Override
91107 public void setAlive (boolean alive ) {
92108 this .alive = alive ;
93109 }
94110
95111 /**
96- * Process the message according to its type.
112+ * Process the given message according to its type.
97113 *
98- * @param message Message polled from queue.
114+ * @param message message to process
99115 */
100116 private void processMessage (Message message ) {
101117 switch (message .getType ()) {
102118 case ELECTION -> {
103- LOGGER .info (INSTANCE + localId + " - Election Message handling ..." );
119+ LOGGER .info ("{}{} - Handling Election Message...", INSTANCE , localId );
104120 handleElectionMessage (message );
105121 }
106122 case LEADER -> {
107- LOGGER .info (INSTANCE + localId + " - Leader Message handling ..." );
123+ LOGGER .info ("{}{} - Handling Leader Message...", INSTANCE , localId );
108124 handleLeaderMessage (message );
109125 }
110126 case HEARTBEAT -> {
111- LOGGER .info (INSTANCE + localId + " - Heartbeat Message handling ..." );
127+ LOGGER .info ("{}{} - Handling Heartbeat Message...", INSTANCE , localId );
112128 handleHeartbeatMessage (message );
113129 }
114130 case ELECTION_INVOKE -> {
115- LOGGER .info (INSTANCE + localId + " - Election Invoke Message handling ..." );
131+ LOGGER .info ("{}{} - Handling Election Invoke...", INSTANCE , localId );
116132 handleElectionInvokeMessage ();
117133 }
118134 case LEADER_INVOKE -> {
119- LOGGER .info (INSTANCE + localId + " - Leader Invoke Message handling ..." );
135+ LOGGER .info ("{}{} - Handling Leader Invoke...", INSTANCE , localId );
120136 handleLeaderInvokeMessage ();
121137 }
122138 case HEARTBEAT_INVOKE -> {
123- LOGGER .info (INSTANCE + localId + " - Heartbeat Invoke Message handling ..." );
139+ LOGGER .info ("{}{} - Handling Heartbeat Invoke...", INSTANCE , localId );
124140 handleHeartbeatInvokeMessage ();
125141 }
126- default -> {}
142+ default -> LOGGER . warn ( "{}{} - Unknown message type received." , INSTANCE , localId );
127143 }
128144 }
129145
130- /**
131- * Abstract methods to handle different types of message. These methods need to be implemented in
132- * concrete instance class to implement corresponding leader-selection pattern.
133- */
146+ // Abstract methods for handling various message types — to be implemented by subclasses.
134147 protected abstract void handleElectionMessage (Message message );
135-
136148 protected abstract void handleElectionInvokeMessage ();
137-
138149 protected abstract void handleLeaderMessage (Message message );
139-
140150 protected abstract void handleLeaderInvokeMessage ();
141-
142151 protected abstract void handleHeartbeatMessage (Message message );
143-
144152 protected abstract void handleHeartbeatInvokeMessage ();
145153}
0 commit comments