diff --git a/pom.xml b/pom.xml index 4cb30df3f..0222d7e37 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ execute-around property intercepting-filter + producer-consumer poison-pill lazy-loading service-layer diff --git a/producer-consumer/etc/producer-consumer.png b/producer-consumer/etc/producer-consumer.png new file mode 100644 index 000000000..e8bc573b3 Binary files /dev/null and b/producer-consumer/etc/producer-consumer.png differ diff --git a/producer-consumer/etc/producer-consumer.ucls b/producer-consumer/etc/producer-consumer.ucls new file mode 100644 index 000000000..aa1ee80c0 --- /dev/null +++ b/producer-consumer/etc/producer-consumer.ucls @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/producer-consumer/index.md b/producer-consumer/index.md new file mode 100644 index 000000000..58dc45e0d --- /dev/null +++ b/producer-consumer/index.md @@ -0,0 +1,22 @@ +--- +layout: pattern +title: Producer Consumer +folder: producer-consumer +permalink: /patterns/producer-consumer/ +categories: Other +tags: Java +--- + +**Intent:** Producer Consumer Design pattern is a classic concurrency or threading pattern which reduces + coupling between Producer and Consumer by separating Identification of work with Execution of + Work.. + + + +![alt text](./etc/producer-consumer.png "Producer Consumer") + +**Applicability:** Use the Producer Consumer idiom when + +* decouple system by separate work in two process produce and consume. +* addresses the issue of different timing require to produce work or consuming work + diff --git a/producer-consumer/pom.xml b/producer-consumer/pom.xml new file mode 100644 index 000000000..475c7fb6c --- /dev/null +++ b/producer-consumer/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.7.0 + + producer-consumer + + + junit + junit + test + + + diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java new file mode 100644 index 000000000..50d94d92f --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/App.java @@ -0,0 +1,57 @@ +package com.iluwatar.producer.consumer; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Producer Consumer Design pattern is a classic concurrency or threading pattern which reduces + * coupling between Producer and Consumer by separating Identification of work with Execution of + * Work. + *

+ * In producer consumer design pattern a shared queue is used to control the flow and this + * separation allows you to code producer and consumer separately. It also addresses the issue of + * different timing require to produce item or consuming item. by using producer consumer pattern + * both Producer and Consumer Thread can work with different speed. + * + */ +public class App { + + /** + * Program entry point + * + * @param args command line args + */ + public static void main(String[] args) { + + ItemQueue queue = new ItemQueue(); + + ExecutorService executorService = Executors.newFixedThreadPool(5); + for (int i = 0; i < 2; i++) { + + final Producer producer = new Producer("Producer_" + i, queue); + executorService.submit(() -> { + while (true) { + producer.produce(); + } + }); + }; + + for (int i = 0; i < 3; i++) { + final Consumer consumer = new Consumer("Consumer_" + i, queue); + executorService.submit(() -> { + while (true) { + consumer.consume(); + } + }); + } + + executorService.shutdown(); + try { + executorService.awaitTermination(10, TimeUnit.SECONDS); + executorService.shutdownNow(); + } catch (InterruptedException e) { + System.out.println("Error waiting for ExecutorService shutdown"); + } + } +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java new file mode 100644 index 000000000..8bb3b75b6 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java @@ -0,0 +1,24 @@ +package com.iluwatar.producer.consumer; + +/** + * Class responsible for consume the {@link Item} produced by {@link Producer} + */ +public class Consumer { + + private final ItemQueue queue; + + private final String name; + + public Consumer(String name, ItemQueue queue) { + this.name = name; + this.queue = queue; + } + + public void consume() throws InterruptedException { + + Item item = queue.take(); + System.out.println(String.format("Consumer [%s] consume item [%s] produced by [%s]", name, + item.getId(), item.getProducer())); + + } +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java new file mode 100644 index 000000000..8d5be69a1 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Item.java @@ -0,0 +1,27 @@ +package com.iluwatar.producer.consumer; + +/** + * Class take part of an {@link Producer}-{@link Consumer} exchange. + */ +public class Item { + + private String producer; + + private int id; + + public Item(String producer, int id) { + this.id = id; + this.producer = producer; + } + + public int getId() { + + return id; + } + + public String getProducer() { + + return producer; + } + +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java new file mode 100644 index 000000000..8d41fb456 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/ItemQueue.java @@ -0,0 +1,27 @@ +package com.iluwatar.producer.consumer; + +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Class as a channel for {@link Producer}-{@link Consumer} exchange. + */ +public class ItemQueue { + + private LinkedBlockingQueue queue; + + public ItemQueue() { + + queue = new LinkedBlockingQueue(5); + } + + public void put(Item item) throws InterruptedException { + + queue.put(item); + } + + public Item take() throws InterruptedException { + + return queue.take(); + } + +} diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java new file mode 100644 index 000000000..40e71c607 --- /dev/null +++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java @@ -0,0 +1,29 @@ +package com.iluwatar.producer.consumer; + +import java.util.Random; + +/** + * Class responsible for producing unit of work that can be expressed as {@link Item} and submitted + * to queue + */ +public class Producer { + + private final ItemQueue queue; + + private final String name; + + private int itemId = 0; + + public Producer(String name, ItemQueue queue) { + this.name = name; + this.queue = queue; + } + + public void produce() throws InterruptedException { + + Item item = new Item(name, itemId++); + queue.put(item); + Random random = new Random(); + Thread.sleep(random.nextInt(2000)); + } +} diff --git a/producer-consumer/src/test/java/com/iluwatar/poison/pill/AppTest.java b/producer-consumer/src/test/java/com/iluwatar/poison/pill/AppTest.java new file mode 100644 index 000000000..26b38dec0 --- /dev/null +++ b/producer-consumer/src/test/java/com/iluwatar/poison/pill/AppTest.java @@ -0,0 +1,20 @@ +package com.iluwatar.poison.pill; + +import org.junit.Test; + +import com.iluwatar.producer.consumer.App; + +/** + * + * Application test + * + */ +public class AppTest { + + @Test + public void test() throws Exception { + String[] args = {}; + App.main(args); + + } +}