My question is purely conceptual. And merely for a deeper understanding of communication between threads.
In a Producer Consumer problem,
The example code is taken from here
package ProducerConsumer;
import java.util.LinkedList;
import java.util.Queue;
public class ClassicProducerConsumerExample {
public static void main(String[] args) throws InterruptedException {
Buffer buffer = new Buffer(2);
Thread producerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
buffer.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread consumerThread = new Thread(new Runnable() {
@Override
public void run() {
try {
buffer.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producerThread.start();
consumerThread.start();
producerThread.join();
consumerThread.join();
}
static class Buffer {
private Queue<Integer> list;
private int size;
public Buffer(int size) {
this.list = new LinkedList<>();
this.size = size;
}
public void produce() throws InterruptedException {
int value = 0;
while (true) {
synchronized (this) {
while (list.size() >= size) {
// wait for the consumer
wait();
}
list.add(value);
System.out.println("Produced " + value);
value++;
// notify the consumer
notify();
Thread.sleep(1000);
}
}
}
public void consume() throws InterruptedException {
while (true) {
synchronized (this) {
while (list.size() == 0) {
// wait for the producer
wait();
}
int value = list.poll();
System.out.println("Consume " + value);
// notify the producer
notify();
Thread.sleep(1000);
}
}
}
}
}
I have read that wait and notify should be inside the synchronized block to avoid race condition.
I don't understand why I should enclose the wait() and notify() in synchronized block when both the threads are calling different methods. Consumer thread is not going to call produce() so if I do not enclose the wait call inside the produce method with synchronized keyword then it should still behave the same because produce() is only being called by the Producer thread. Is that right?
The buffer which both threads are adding/removing from, is a linked list. Java's linked list is not thread safe.
However, you can abstract out this locking into the data structure itself by using a concurrent version.
Another fallout: While in this example there is only producer and only one consumer, that may not be the case always. Having more than one producer and/or consumer may have a use case where synchronization is required, even for a thread-safe data structure.