Leader/Followers
Intent
The Leader/Followers design pattern is a pattern used to coordinate a selection of 'workers'. It allows tasks to execute concurrently
with the Leader delegating tasks to the Follower threads for execution. It is a very common design pattern used in multithreaded
situations such as servers, and works to help prevent ambiguity around delegation of tasks.
Explanation
Real-world Example
The best real world example of Leader/Followers is a web server. Web servers have to be able to handle a multitude of incoming
connections all at once. In a web server, the Leader/Followers pattern works by using the Leader to listen to incoming requests
and accept connections. Once a connection is made to a client the Leader can then find a Follower thread to delegate the task
to for execution and return to the client. This means that the Leader does not have to wait to finish execution before it can
accept another incoming connection, and can focus on delegating tasks. This pattern is created to aid in concurrency of applicaitons,
allowing for many connections to work simultaneously.
In plain words
You can picture the Leader as a traffic controller that has to direct traffic from one lane into 25 lanes. As a car comes in,
the Leader sends it down a road that isn't full or busy. This car can then have its request filled, or reach its destination.
If the Leader had to drive each car down the lane itself, the line would pile up and progress would be slow. But as the Leader
has Followers that can also drive the cars, the Leader can focus on making the line move quickly and ensuring traffic doesn't
back up.
Wikipedia says
A concurrency pattern are those types of design patterns that deal with the multi-threaded programming paradigm.
Programmatic Example
This example shows Java code that sets up a Leader that listens for client requests on port 8080. Once a request is sent,
the leader will accept it and delegate it to a new Follower to execute. This means that the Leader can keep delegating,
and ensure requests are fulfilled timely. This is only pseudocode and the working code would require a more concrete implementation
of Leader and Followers.
public class LeaderFollowerWebServer {
public static void main(String[] args) throws IOException {
int port = 8080; // the port that clients can reach the leader on
int numFollowers = 5; // the amount of followers we can delegate tasks to
ServerSocket serverSocket = new ServerSocket(port); // pseudocode for creating a socket to the server
ExecutorService executorService = Executors.newFixedThreadPool(numFollowers); // pseudocode to start execution for Followers
System.out.println("Web server started. Listening on port " + port);
while (true) {
Socket clientSocket = serverSocket.accept();
// Accept a new connection and assign it to a follower thread for processing
executorService.execute(new Follower(clientSocket));
}
}
}
class Follower implements Runnable {
private final Socket clientSocket;
public Follower(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
try {
// handle the client request, e.g., read and write data
// this is where you would implement your request processing logic.
// we will just close the socket
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Class diagram
Applicability
Use Leader-Followers pattern when
- You want to establish a concurrent application
- You want faster response times on heavy load
- You want an easily scalable program
- You want to load balance a program
Consequences
Consequences involved with using the Leader/Followers pattern
- Implementing this pattern will increase complexity of the code
- If the leader is too slow at delegating processes, some Followers may not get to execute tasks leading to a waste of resources
- There is overhead with organising and maintaining a thread pool
- Debugging is more complex
Real world examples
- ACE Thread Pool Reactor framework
- JAWS
- Real-time CORBA
Credits
- Douglas C. Schmidt and Carlos O’Ryan - Leader/Followers