Java Program with wait() and notify() for Thread Synchronization
Java Multithreading: Exercise-2 with Solution
Write a Java program to create a producer-consumer scenario using the wait() and notify() methods for thread synchronization.
Sample Solution-1:
Java Code:
// ProducerConsumer.java
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumer {
private static final int BUFFER_SIZE = 5;
private static final Queue < Integer > buffer = new LinkedList < > ();
public static void main(String[] args) {
Thread producerThread = new Thread(new Producer());
Thread consumerThread = new Thread(new Consumer());
producerThread.start();
consumerThread.start();
}
static class Producer implements Runnable {
public void run() {
int value = 0;
while (true) {
synchronized(buffer) {
// Wait if the buffer is full
while (buffer.size() == BUFFER_SIZE) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Producer produced: " + value);
buffer.add(value++);
// Notify the consumer that an item is produced
buffer.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class Consumer implements Runnable {
public void run() {
while (true) {
synchronized(buffer) {
// Wait if the buffer is empty
while (buffer.isEmpty()) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int value = buffer.poll();
System.out.println("Consumer consumed: " + value);
// Notify the producer that an item is consumed
buffer.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
Sample Output:
Producer produced: 0 Producer produced: 1 Consumer consumed: 0 Consumer consumed: 1 Producer produced: 2 Producer produced: 3 Producer produced: 4 Producer produced: 5 Producer produced: 6 Consumer consumed: 2 Consumer consumed: 3 Consumer consumed: 4 Consumer consumed: 5 Consumer consumed: 6 Producer produced: 7 Producer produced: 8 Producer produced: 9 Producer produced: 10 Producer produced: 11 ................................... ...................................
Explanation:
In the above exercise -
- The "Producer" class implements the Runnable interface and represents the producer thread. It continuously produces items by adding values to the shared buffer. When the buffer is full, the producer waits until the consumer consumes an item and notifies it.
- The "Consumer" class also implements the Runnable interface and represents the consumer thread. It continuously consumes items by removing values from the shared buffer. As soon as the buffer is empty, the consumer uses the wait() method to wait until a new item is produced by the producer.
- In the main() method, we create instances of the Producer and Consumer classes as separate threads and start them concurrently.
Flowchart:
Sample Solution-2:
The code we provided above has a potential issue with deadlock, and using notifyAll() is a good solution to avoid it. Here's an updated version of the above code with notifyAll():
Java Code:
// ProducerConsumer.java
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumer {
private static final int BUFFER_SIZE = 5;
private static final Queue<Integer> buffer = new LinkedList<>();
public static void main(String[] args) {
// Create producer and consumer threads
Thread producerThread = new Thread(new Producer());
Thread consumerThread = new Thread(new Consumer());
// Start producer and consumer threads
producerThread.start();
consumerThread.start();
}
// Producer thread class
static class Producer implements Runnable {
public void run() {
int value = 0;
while (true) {
synchronized (buffer) {
// Wait if the buffer is full
while (buffer.size() == BUFFER_SIZE) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Produce item and add to the buffer
System.out.println("Producer produced: " + value);
buffer.add(value++);
// Notify all consumers that an item is produced
buffer.notifyAll();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
// Consumer thread class
static class Consumer implements Runnable {
public void run() {
while (true) {
synchronized (buffer) {
// Wait if the buffer is empty
while (buffer.isEmpty()) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Consume item from the buffer
int value = buffer.poll();
System.out.println("Consumer consumed: " + value);
// Notify all producers that an item is consumed
buffer.notifyAll();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
Sample Output:
Producer produced: 0 Producer produced: 1 Producer produced: 2 Producer produced: 3 Producer produced: 4 Consumer consumed: 0 Consumer consumed: 1 Consumer consumed: 2 Consumer consumed: 3 Consumer consumed: 4 Producer produced: 5 Producer produced: 6 Producer produced: 7 Producer produced: 8 Producer produced: 9 Consumer consumed: 5 Consumer consumed: 6 Consumer consumed: 7 ......... .........
Java Code Editor:
Improve this sample solution and post your code through Disqus
Previous: Java Program to Create and Start Multiple Threads.
Next: Synchronizing Threads with ReentrantLock for Shared Resource.
What is the difficulty level of this exercise?
Test your Programming skills with w3resource's quiz.
It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.
https://www.w3resource.com/java-exercises/multithreading/java-multithreading-exercise-2.php
- Weekly Trends and Language Statistics
- Weekly Trends and Language Statistics