Skip to content

Commit 3605f8f

Browse files
authored
docs: Adding explanation for Producer-Consumer Design Pattern (iluwatar#2179)
1 parent 6f21b10 commit 3605f8f

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

producer-consumer/README.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,114 @@ Producer Consumer Design pattern is a classic concurrency pattern which reduces
1111
coupling between Producer and Consumer by separating Identification of work with Execution of
1212
Work.
1313

14+
## Explanation
15+
16+
Real-world example
17+
18+
> Consider a manufacturing process of item, the producer will need to pause the production when
19+
> manufacturing pipeline is full and the consumer will need to pause the consumption of item
20+
> when the manufacturing pipeline is empty. We can separate the process of production and consumption
21+
> which work together and pause at separate times.
22+
23+
In plain words
24+
25+
> It provides a way to share data between multiple loops running at different rates.
26+
27+
Wikipedia says
28+
> Dijkstra wrote about the case: "We consider two processes, which are called the 'producer'
29+
> and the 'consumer' respectively. The producer is a cyclic process that produces a certain
30+
> portion of information, that has to be processed by the consumer. The consumer is also a cyclic
31+
> process that needs to process the next portion of information, as has been produced by the producer
32+
> We assume the two processes to be connected for this purpose via a buffer with unbounded capacity."
33+
34+
**Programmatic Example**
35+
36+
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`.
37+
38+
```java
39+
public class Producer {
40+
41+
private static final SecureRandom RANDOM = new SecureRandom();
42+
43+
private final ItemQueue queue;
44+
45+
private final String name;
46+
47+
private int itemId;
48+
49+
public Producer(String name, ItemQueue queue) {
50+
this.name = name;
51+
this.queue = queue;
52+
}
53+
54+
/**
55+
* Put item in the queue.
56+
*/
57+
public void produce() throws InterruptedException {
58+
59+
var item = new Item(name, itemId++);
60+
queue.put(item);
61+
Thread.sleep(RANDOM.nextInt(2000));
62+
}
63+
}
64+
65+
```
66+
67+
Then, we have the `Consumer` class that takes the item from the item queue.
68+
69+
```java
70+
71+
@Slf4j
72+
public class Consumer {
73+
74+
private final ItemQueue queue;
75+
76+
private final String name;
77+
78+
public Consumer(String name, ItemQueue queue) {
79+
this.name = name;
80+
this.queue = queue;
81+
}
82+
83+
/**
84+
* Consume item from the queue.
85+
*/
86+
public void consume() throws InterruptedException {
87+
var item = queue.take();
88+
LOGGER.info("Consumer [{}] consume item [{}] produced by [{}]", name,
89+
item.getId(), item.getProducer());
90+
91+
}
92+
}
93+
```
94+
95+
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.
96+
97+
```java
98+
var queue = new ItemQueue();
99+
var executorService = Executors.newFixedThreadPool(5);
100+
for (var i = 0; i < 2; i++) {
101+
102+
final var producer = new Producer("Producer_" + i, queue);
103+
executorService.submit(() -> {
104+
while (true) {
105+
producer.produce();
106+
}
107+
});
108+
}
109+
110+
for (var i = 0; i < 3; i++) {
111+
final var consumer = new Consumer("Consumer_" + i, queue);
112+
executorService.submit(() -> {
113+
while (true) {
114+
consumer.consume();
115+
}
116+
});
117+
}
118+
119+
```
120+
121+
14122
## Class diagram
15123
![alt text](./etc/producer-consumer.png "Producer Consumer")
16124

0 commit comments

Comments
 (0)