From 82842d614b0fb76c4adaeba7b69e656621dbbf0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 30 Aug 2020 20:08:34 +0300 Subject: [PATCH] Update README.md --- priority-queue/README.md | 192 +++++++++++++++++- .../iluwatar/priority/queue/Application.java | 7 +- .../iluwatar/priority/queue/QueueManager.java | 2 +- 3 files changed, 192 insertions(+), 9 deletions(-) diff --git a/priority-queue/README.md b/priority-queue/README.md index 924d7169f..8481915be 100644 --- a/priority-queue/README.md +++ b/priority-queue/README.md @@ -10,19 +10,203 @@ tags: --- ## Intent -Prioritize requests sent to services so that requests with a higher priority are received and processed more quickly than those of a lower priority. This pattern is useful in applications that offer different service level guarantees to individual clients. + +Prioritize requests sent to services so that requests with a higher priority are received and +processed more quickly than those of a lower priority. This pattern is useful in applications that +offer different service level guarantees to individual clients. ## Explanation -Applications may delegate specific tasks to other services; for example, to perform background processing or to integrate with other applications or services. In the cloud, a message queue is typically used to delegate tasks to background processing. In many cases the order in which requests are received by a service is not important. However, in some cases it may be necessary to prioritize specific requests. These requests should be processed earlier than others of a lower priority that may have been sent previously by the application. + +Applications may delegate specific tasks to other services; for example, to perform background +processing or to integrate with other applications or services. In the cloud, a message queue is +typically used to delegate tasks to background processing. In many cases the order in which requests +are received by a service is not important. However, in some cases it may be necessary to prioritize +specific requests. These requests should be processed earlier than others of a lower priority that +may have been sent previously by the application. + +Real world example + +> Imagine a video processing service with free and premium customers. The requests coming from the +> paying premium customers should be prioritized over the others. + +In plain words + +> Priority Queue enables processing of high priority messages first, regardless of queue size or +> message age. + +Wikipedia says + +> In computer science, a priority queue is an abstract data type similar to regular queue or stack +> data structure in which each element additionally has a "priority" associated with it. In a +> priority queue, an element with high priority is served before an element with low priority. + +**Programmatic Example** + +Looking at the video processing example from above, let's first see the `Message` structure. + +```java +public class Message implements Comparable { + + private final String message; + private final int priority; // define message priority in queue + + public Message(String message, int priority) { + this.message = message; + this.priority = priority; + } + + @Override + public int compareTo(Message o) { + return priority - o.priority; + } + ... +} +``` + +Here's `PriorityMessageQueue` that handles storing the messages and serving them in priority +order. + +```java +public class PriorityMessageQueue { + + ... + + public T remove() { + if (isEmpty()) { + return null; + } + + final var root = queue[0]; + queue[0] = queue[size - 1]; + size--; + maxHeapifyDown(); + return root; + } + + public void add(T t) { + ensureCapacity(); + queue[size] = t; + size++; + maxHeapifyUp(); + } + + ... +} +``` + +`QueueManager` has a `PriorityMessageQueue` and makes it easy to `publishMessage` and +`receiveMessage`. + +```java +public class QueueManager { + + private final PriorityMessageQueue messagePriorityMessageQueue; + + public QueueManager(int initialCapacity) { + messagePriorityMessageQueue = new PriorityMessageQueue<>(new Message[initialCapacity]); + } + + public void publishMessage(Message message) { + messagePriorityMessageQueue.add(message); + } + + public Message receiveMessage() { + if (messagePriorityMessageQueue.isEmpty()) { + return null; + } + return messagePriorityMessageQueue.remove(); + } +} +``` + +`Worker` constantly polls `QueueManager` for highest priority message and processes it. + +```java +public class Worker { + + private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class); + + private final QueueManager queueManager; + + public Worker(QueueManager queueManager) { + this.queueManager = queueManager; + } + + public void run() throws Exception { + while (true) { + var message = queueManager.receiveMessage(); + if (message == null) { + LOGGER.info("No Message ... waiting"); + Thread.sleep(200); + } else { + processMessage(message); + } + } + } + + private void processMessage(Message message) { + LOGGER.info(message.toString()); + } +} +``` + +Here's the full example how we create an instance of `QueueManager` and process messages using +`Worker`. + +```java + var queueManager = new QueueManager(100); + + for (var i = 0; i < 100; i++) { + queueManager.publishMessage(new Message("Low Message Priority", 0)); + } + + for (var i = 0; i < 100; i++) { + queueManager.publishMessage(new Message("High Message Priority", 1)); + } + + var worker = new Worker(queueManager); + worker.run(); +``` + +Program output: + +``` +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='High Message Priority', priority=1} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +Message{message='Low Message Priority', priority=0} +No Message ... waiting +No Message ... waiting +No Message ... waiting +``` + ## Class diagram + ![alt text](./etc/priority-queue.urm.png "Priority Queue pattern class diagram") ## Applicability -Use the Priority Queue pattern when + +Use the Priority Queue pattern when: * The system must handle multiple tasks that might have different priorities. -* Different users or tenants should be served with different priority.. +* Different users or tenants should be served with different priority. ## Credits diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java index 433a72d74..cdef90ab8 100644 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java +++ b/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java @@ -37,20 +37,19 @@ public class Application { */ public static void main(String[] args) throws Exception { - var queueManager = new QueueManager(100); + var queueManager = new QueueManager(10); // push some message to queue // Low Priority message - for (var i = 0; i < 100; i++) { + for (var i = 0; i < 10; i++) { queueManager.publishMessage(new Message("Low Message Priority", 0)); } // High Priority message - for (var i = 0; i < 100; i++) { + for (var i = 0; i < 10; i++) { queueManager.publishMessage(new Message("High Message Priority", 1)); } - // run worker var worker = new Worker(queueManager); worker.run(); diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java index 0b4be910f..3a0761f4a 100644 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java +++ b/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java @@ -45,7 +45,7 @@ public class QueueManager { /** - * recive message from queue. + * Receive message from queue. */ public Message receiveMessage() { if (messagePriorityMessageQueue.isEmpty()) {