--- title: Producer Consumer category: Concurrency language: en tag: - Reactive --- ## Intent Producer Consumer Design pattern is a classic concurrency pattern which reduces coupling between Producer and Consumer by separating Identification of work with Execution of Work. ## Explanation Real-world example > Consider a manufacturing process of item, the producer will need to pause the production when > manufacturing pipeline is full and the consumer will need to pause the consumption of item > when the manufacturing pipeline is empty. We can separate the process of production and consumption > which work together and pause at separate times. In plain words > It provides a way to share data between multiple loops running at different rates. Wikipedia says > Dijkstra wrote about the case: "We consider two processes, which are called the 'producer' > and the 'consumer' respectively. The producer is a cyclic process that produces a certain > portion of information, that has to be processed by the consumer. The consumer is also a cyclic > process that needs to process the next portion of information, as has been produced by the producer > We assume the two processes to be connected for this purpose via a buffer with unbounded capacity." **Programmatic Example** Take our Producer and Consumer example from above. Consider we have a `Item` class that is produced by `Producer` class and is added to the `ItemQueue`. ```java public class Producer { private static final SecureRandom RANDOM = new SecureRandom(); private final ItemQueue queue; private final String name; private int itemId; public Producer(String name, ItemQueue queue) { this.name = name; this.queue = queue; } /** * Put item in the queue. */ public void produce() throws InterruptedException { var item = new Item(name, itemId++); queue.put(item); Thread.sleep(RANDOM.nextInt(2000)); } } ``` Then, we have the `Consumer` class that takes the item from the item queue. ```java @Slf4j public class Consumer { private final ItemQueue queue; private final String name; public Consumer(String name, ItemQueue queue) { this.name = name; this.queue = queue; } /** * Consume item from the queue. */ public void consume() throws InterruptedException { var item = queue.take(); LOGGER.info("Consumer [{}] consume item [{}] produced by [{}]", name, item.getId(), item.getProducer()); } } ``` Now, during the manufacturing pipeline, we can instantiate objects from both the `Producer` and `Consumer` clasess as they produce and consumer items from the queue. ```java var queue = new ItemQueue(); var executorService = Executors.newFixedThreadPool(5); for (var i = 0; i < 2; i++) { final var producer = new Producer("Producer_" + i, queue); executorService.submit(() -> { while (true) { producer.produce(); } }); } for (var i = 0; i < 3; i++) { final var consumer = new Consumer("Consumer_" + i, queue); executorService.submit(() -> { while (true) { consumer.consume(); } }); } ``` ## Class diagram ![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