* add leader followers pattern * use var and streams instead in App::execute * use logger instead of printing to system output stream
This commit is contained in:
parent
6ce33ed6df
commit
be1c0b8143
32
leader-followers/README.md
Normal file
32
leader-followers/README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
layout: pattern
|
||||||
|
title: Leader/Followers
|
||||||
|
folder: leader-followers
|
||||||
|
permalink: /patterns/leader-followers/
|
||||||
|
categories: Concurrency
|
||||||
|
tags:
|
||||||
|
- Performance
|
||||||
|
---
|
||||||
|
|
||||||
|
## Intent
|
||||||
|
The Leader/Followers pattern provides a concurrency model where multiple
|
||||||
|
threads can efficiently de-multiplex events and dispatch event handlers
|
||||||
|
that process I/O handles shared by the threads.
|
||||||
|
|
||||||
|
## Class diagram
|
||||||
|

|
||||||
|
|
||||||
|
## Applicability
|
||||||
|
Use Leader-Followers pattern when
|
||||||
|
|
||||||
|
* multiple threads take turns sharing a set of event sources in order to detect, de-multiplex, dispatch and process service requests that occur on the event sources.
|
||||||
|
|
||||||
|
## Real world examples
|
||||||
|
|
||||||
|
* [ACE Thread Pool Reactor framework](https://www.dre.vanderbilt.edu/~schmidt/PDF/HPL.pdf)
|
||||||
|
* [JAWS](http://www.dre.vanderbilt.edu/~schmidt/PDF/PDCP.pdf)
|
||||||
|
* [Real-time CORBA](http://www.dre.vanderbilt.edu/~schmidt/PDF/RTS.pdf)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
* [Douglas C. Schmidt and Carlos O’Ryan - Leader/Followers](http://www.kircher-schwanninger.de/michael/publications/lf.pdf)
|
BIN
leader-followers/etc/leader-followers.png
Normal file
BIN
leader-followers/etc/leader-followers.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
54
leader-followers/etc/leader-followers.urm.puml
Normal file
54
leader-followers/etc/leader-followers.urm.puml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
@startuml
|
||||||
|
package com.iluwatar.leaderfollowers {
|
||||||
|
class App {
|
||||||
|
+ App()
|
||||||
|
- addTasks(taskSet : TaskSet) {static}
|
||||||
|
- execute(workCenter : WorkCenter, taskSet : TaskSet) {static}
|
||||||
|
+ main(args : String[]) {static}
|
||||||
|
}
|
||||||
|
class Task {
|
||||||
|
- finished : boolean
|
||||||
|
- time : int
|
||||||
|
+ Task(time : int)
|
||||||
|
+ getTime() : int
|
||||||
|
+ isFinished() : boolean
|
||||||
|
+ setFinished()
|
||||||
|
}
|
||||||
|
class TaskHandler {
|
||||||
|
+ TaskHandler()
|
||||||
|
+ handleTask(task : Task)
|
||||||
|
}
|
||||||
|
class TaskSet {
|
||||||
|
- queue : BlockingQueue<Task>
|
||||||
|
+ TaskSet()
|
||||||
|
+ addTask(task : Task)
|
||||||
|
+ getSize() : int
|
||||||
|
+ getTask() : Task
|
||||||
|
}
|
||||||
|
class WorkCenter {
|
||||||
|
- leader : Worker
|
||||||
|
- workers : List<Worker>
|
||||||
|
+ WorkCenter()
|
||||||
|
+ addWorker(worker : Worker)
|
||||||
|
+ createWorkers(numberOfWorkers : int, taskSet : TaskSet, taskHandler : TaskHandler)
|
||||||
|
+ getLeader() : Worker
|
||||||
|
+ getWorkers() : List<Worker>
|
||||||
|
+ promoteLeader()
|
||||||
|
+ removeWorker(worker : Worker)
|
||||||
|
}
|
||||||
|
class Worker {
|
||||||
|
- id : long
|
||||||
|
- taskHandler : TaskHandler
|
||||||
|
- taskSet : TaskSet
|
||||||
|
- workCenter : WorkCenter
|
||||||
|
+ Worker(id : long, workCenter : WorkCenter, taskSet : TaskSet, taskHandler : TaskHandler)
|
||||||
|
+ equals(o : Object) : boolean
|
||||||
|
+ hashCode() : int
|
||||||
|
+ run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Worker --> "-taskSet" TaskSet
|
||||||
|
Worker --> "-taskHandler" TaskHandler
|
||||||
|
TaskSet --> "-queue" Task
|
||||||
|
Worker --> "-workCenter" WorkCenter
|
||||||
|
@enduml
|
46
leader-followers/pom.xml
Normal file
46
leader-followers/pom.xml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.iluwatar</groupId>
|
||||||
|
<artifactId>java-design-patterns</artifactId>
|
||||||
|
<version>1.23.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>leader-followers</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Leader/Followers pattern is a concurrency pattern. This pattern behaves like a taxi stand where
|
||||||
|
* one of the threads acts as leader thread which listens for event from event sources,
|
||||||
|
* de-multiplexes, dispatches and handles the event. It promotes the follower to be the new leader.
|
||||||
|
* When processing completes the thread joins the followers queue, if there are no followers then it
|
||||||
|
* becomes the leader and cycle repeats again.
|
||||||
|
*
|
||||||
|
* <p>In this example, one of the workers becomes Leader and listens on the {@link TaskSet} for
|
||||||
|
* work. {@link TaskSet} basically acts as the source of input events for the {@link Worker}, who
|
||||||
|
* are spawned and controlled by the {@link WorkCenter} . When {@link Task} arrives then the leader
|
||||||
|
* takes the work and calls the {@link TaskHandler}. It also calls the {@link WorkCenter} to
|
||||||
|
* promotes one of the followers to be the new leader, who can then process the next work and so
|
||||||
|
* on.
|
||||||
|
*
|
||||||
|
* <p>The pros for this pattern are:
|
||||||
|
* It enhances CPU cache affinity and eliminates unbound allocation and data buffer sharing between
|
||||||
|
* threads by reading the request into buffer space allocated on the stack of the leader or by using
|
||||||
|
* the Thread-Specific Storage pattern [22] to allocate memory. It minimizes locking overhead by not
|
||||||
|
* exchanging data between threads, thereby reducing thread synchronization. In bound handle/thread
|
||||||
|
* associations, the leader thread dispatches the event based on the I/O handle. It can minimize
|
||||||
|
* priority inversion because no extra queuing is introduced in the server. It does not require a
|
||||||
|
* context switch to handle each event, reducing the event dispatching latency. Note that promoting
|
||||||
|
* a follower thread to fulfill the leader role requires a context switch. Programming simplicity:
|
||||||
|
* The Leader/Followers pattern simplifies the programming of concurrency models where multiple
|
||||||
|
* threads can receive requests, process responses, and de-multiplex connections using a shared
|
||||||
|
* handle set.
|
||||||
|
*/
|
||||||
|
public class App {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main method for the leader followers pattern.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
var taskSet = new TaskSet();
|
||||||
|
var taskHandler = new TaskHandler();
|
||||||
|
var workCenter = new WorkCenter();
|
||||||
|
workCenter.createWorkers(4, taskSet, taskHandler);
|
||||||
|
execute(workCenter, taskSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the work, dispatch tasks and stop the thread pool at last.
|
||||||
|
*/
|
||||||
|
private static void execute(WorkCenter workCenter, TaskSet taskSet) throws InterruptedException {
|
||||||
|
var workers = workCenter.getWorkers();
|
||||||
|
var exec = Executors.newFixedThreadPool(workers.size());
|
||||||
|
workers.forEach(exec::submit);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
addTasks(taskSet);
|
||||||
|
exec.awaitTermination(2, TimeUnit.SECONDS);
|
||||||
|
exec.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add tasks.
|
||||||
|
*/
|
||||||
|
private static void addTasks(TaskSet taskSet) throws InterruptedException {
|
||||||
|
var rand = new Random();
|
||||||
|
for (var i = 0; i < 5; i++) {
|
||||||
|
var time = Math.abs(rand.nextInt(1000));
|
||||||
|
taskSet.addTask(new Task(time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unit of work to be processed by the Workers.
|
||||||
|
*/
|
||||||
|
public class Task {
|
||||||
|
|
||||||
|
private final int time;
|
||||||
|
|
||||||
|
private boolean finished;
|
||||||
|
|
||||||
|
public Task(int time) {
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFinished() {
|
||||||
|
this.finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished() {
|
||||||
|
return this.finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TaskHandler is used by the {@link Worker} to process the newly arrived task.
|
||||||
|
*/
|
||||||
|
public class TaskHandler {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(TaskHandler.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface handles one task at a time.
|
||||||
|
*/
|
||||||
|
public void handleTask(Task task) throws InterruptedException {
|
||||||
|
var time = task.getTime();
|
||||||
|
Thread.sleep(time);
|
||||||
|
LOGGER.info("It takes " + time + " milliseconds to finish the task");
|
||||||
|
task.setFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A TaskSet is a collection of the tasks, the leader receives task from here.
|
||||||
|
*/
|
||||||
|
public class TaskSet {
|
||||||
|
|
||||||
|
private BlockingQueue<Task> queue = new ArrayBlockingQueue<>(100);
|
||||||
|
|
||||||
|
public void addTask(Task task) throws InterruptedException {
|
||||||
|
queue.put(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task getTask() throws InterruptedException {
|
||||||
|
return queue.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return queue.size();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A WorkCenter contains a leader and a list of idle workers. The leader is responsible for
|
||||||
|
* receiving work when it arrives. This class also provides a mechanism to promote a new leader. A
|
||||||
|
* worker once he completes his task will add himself back to the center.
|
||||||
|
*/
|
||||||
|
public class WorkCenter {
|
||||||
|
|
||||||
|
private Worker leader;
|
||||||
|
private List<Worker> workers = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create workers and set leader.
|
||||||
|
*/
|
||||||
|
public void createWorkers(int numberOfWorkers, TaskSet taskSet, TaskHandler taskHandler) {
|
||||||
|
for (var id = 1; id <= numberOfWorkers; id++) {
|
||||||
|
var worker = new Worker(id, this, taskSet, taskHandler);
|
||||||
|
workers.add(worker);
|
||||||
|
}
|
||||||
|
promoteLeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addWorker(Worker worker) {
|
||||||
|
workers.add(worker);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeWorker(Worker worker) {
|
||||||
|
workers.remove(worker);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Worker getLeader() {
|
||||||
|
return leader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promote a leader.
|
||||||
|
*/
|
||||||
|
public void promoteLeader() {
|
||||||
|
Worker leader = null;
|
||||||
|
if (workers.size() > 0) {
|
||||||
|
leader = workers.get(0);
|
||||||
|
}
|
||||||
|
this.leader = leader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Worker> getWorkers() {
|
||||||
|
return workers;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class Worker implements Runnable {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class);
|
||||||
|
|
||||||
|
private final long id;
|
||||||
|
private final WorkCenter workCenter;
|
||||||
|
private final TaskSet taskSet;
|
||||||
|
private final TaskHandler taskHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to create a worker which will take work from the work center.
|
||||||
|
*/
|
||||||
|
public Worker(long id, WorkCenter workCenter, TaskSet taskSet, TaskHandler taskHandler) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.workCenter = workCenter;
|
||||||
|
this.taskSet = taskSet;
|
||||||
|
this.taskHandler = taskHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The leader thread listens for task. When task arrives, it promotes one of the followers to be
|
||||||
|
* the new leader. Then it handles the task and add himself back to work center.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
try {
|
||||||
|
if (workCenter.getLeader() != null && !workCenter.getLeader().equals(this)) {
|
||||||
|
synchronized (workCenter) {
|
||||||
|
workCenter.wait();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final Task task = taskSet.getTask();
|
||||||
|
synchronized (workCenter) {
|
||||||
|
workCenter.removeWorker(this);
|
||||||
|
workCenter.promoteLeader();
|
||||||
|
workCenter.notifyAll();
|
||||||
|
}
|
||||||
|
taskHandler.handleTask(task);
|
||||||
|
LOGGER.info("The Worker with the ID " + id + " completed the task");
|
||||||
|
workCenter.addWorker(this);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOGGER.warn("Worker interrupted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof Worker)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var worker = (Worker) o;
|
||||||
|
return id == worker.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Application test
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AppTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() throws InterruptedException {
|
||||||
|
String[] args = {};
|
||||||
|
App.main(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for TaskHandler
|
||||||
|
*/
|
||||||
|
public class TaskHandlerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandleTask() throws InterruptedException {
|
||||||
|
var taskHandler = new TaskHandler();
|
||||||
|
var handle = new Task(100);
|
||||||
|
taskHandler.handleTask(handle);
|
||||||
|
Assert.assertTrue(handle.isFinished());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for TaskSet
|
||||||
|
*/
|
||||||
|
public class TaskSetTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddTask() throws InterruptedException {
|
||||||
|
var taskSet = new TaskSet();
|
||||||
|
taskSet.addTask(new Task(10));
|
||||||
|
Assert.assertTrue(taskSet.getSize() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTask() throws InterruptedException {
|
||||||
|
var taskSet = new TaskSet();
|
||||||
|
taskSet.addTask(new Task(100));
|
||||||
|
Task task = taskSet.getTask();
|
||||||
|
Assert.assertTrue(task.getTime() == 100);
|
||||||
|
Assert.assertTrue(taskSet.getSize() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2019 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.iluwatar.leaderfollowers;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for WorkCenter
|
||||||
|
*/
|
||||||
|
public class WorkCenterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateWorkers() {
|
||||||
|
var taskSet = new TaskSet();
|
||||||
|
var taskHandler = new TaskHandler();
|
||||||
|
var workCenter = new WorkCenter();
|
||||||
|
workCenter.createWorkers(5, taskSet, taskHandler);
|
||||||
|
Assert.assertEquals(workCenter.getWorkers().size(), 5);
|
||||||
|
Assert.assertEquals(workCenter.getWorkers().get(0), workCenter.getLeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullLeader() {
|
||||||
|
var workCenter = new WorkCenter();
|
||||||
|
workCenter.promoteLeader();
|
||||||
|
Assert.assertNull(workCenter.getLeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPromoteLeader() {
|
||||||
|
var taskSet = new TaskSet();
|
||||||
|
var taskHandler = new TaskHandler();
|
||||||
|
var workCenter = new WorkCenter();
|
||||||
|
workCenter.createWorkers(5, taskSet, taskHandler);
|
||||||
|
workCenter.removeWorker(workCenter.getLeader());
|
||||||
|
workCenter.promoteLeader();
|
||||||
|
Assert.assertEquals(workCenter.getWorkers().size(), 4);
|
||||||
|
Assert.assertEquals(workCenter.getWorkers().get(0), workCenter.getLeader());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user