The producer-consumer pattern is a common synchronization pattern in multi-threaded programming, where one thread (the producer) produces data and another thread (the consumer) consumes the data. The producer and consumer threads must communicate and coordinate with each other to ensure that the data is produced and consumed in the correct order.
In Java, there are several ways to implement a producer-consumer pattern, including using wait() and notify() methods, using BlockingQueue, and using ExecutorService. Here’s an example of how to implement a producer-consumer pattern using wait() and notify() methods:
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumerExample {
private final Queue<Integer> queue = new LinkedList<>();
private final int MAX_SIZE = 10;
public void produce() throws InterruptedException {
while (true) {
synchronized (queue) {
while (queue.size() == MAX_SIZE) {
queue.wait();
}
int value = produceValue();
queue.add(value);
System.out.println("Produced: " + value);
queue.notifyAll();
}
Thread.sleep(1000);
}
}
public void consume() throws InterruptedException {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait();
}
int value = queue.poll();
System.out.println("Consumed: " + value);
queue.notifyAll();
}
Thread.sleep(1000);
}
}
private int produceValue() {
return (int) (Math.random() * 100);
}
public static void main(String[] args) {
ProducerConsumerExample example = new ProducerConsumerExample();
new Thread(() -> {
try {
example.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
example.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
In this example, the produce() and consume() methods are synchronized on the queue object using the synchronized keyword. The produce() method checks if the queue is full using a while loop, and waits for the consumer thread to consume data using the queue.wait() method. Once the queue is not full, the produceValue() method generates a random value to add to the queue, and the value is added using the queue.add() method. The produce() method then notifies the consumer thread using the queue.notifyAll() method.
The consume() method checks if the queue is empty using a while loop, and waits for the producer thread to produce data using the queue.wait() method. Once the queue is not empty, the consumer thread consumes data using the queue.poll() method. The consume() method then notifies the producer thread using the queue.notifyAll() method.
To run this example, simply compile the Java file and run the main method:
javac ProducerConsumerExample.java
java ProducerConsumerExample
Overall, the producer-consumer pattern is an important synchronization pattern in multi-threaded programming, and there are several ways to implement it in Java using different synchronization primitives.