Search code examples
javamultithreadingsynchronized

Two Class Synchronization


I have 4 classes: Main, Producer, Consumer, and Buffer. The buffer class contains the implementation for a circular array (assume it works). The producer class adds to the buffer array and the consumer class removes from the buffer array. The Main class creates a thread for producer and for consumer.

Inside the producer class, if the buffer is not full, it adds to it. If it is full, it waits until consumer removes something from the array.

Inside the Consumer class, if the buffer is not empty, it removes an item from it. If it is empty, it waits until producer adds something to the buffer.

The problem I'm having is that producer will add items to the array, but each time it notifies the consumer that it has added to the buffer, the consumer stays in the waiting state. It never continues with the rest of the code.

// Main.java
Buffer buffer = new Buffer(5); // creates a circular array of length 5.

// 10 is total number of items to be added
Producer p = new Producer(buffer, 10); // uses random number generator for values 
Consumer c = new Consumer(buffer, 10);

p.start();
c.start();

p.join();
c.join();
public class Producer extends Thread {

    ...

    public void run() { 
        ...
        while(true) {
            synchronized(this) {
                try {
                    while(buffer.isFull()) wait(); 
                    ...
                    buffer.insert(val);
                    notify();
                    ... // other stuff that eventually breaks the loop
                } catch(InterruptedException e) {}
            }
        }
    }
}
public class Consumer extends Thread {

    ...

    public void run() {
        while(true) {
            synchronized(this) {
                try {
                    while(buffer.isEmpty()) wait(); // its stuck here
                    ...
                    buffer.remove();
                    notify();
                    ... // other stuff that eventually breaks the loop
                } catch (InterruptedException e) {}
            }
        }
    }
}

// Inside Buffer.java

public void insert(int n) {
    ...
    buffer[front] = n;
    front++;
    size++;
}

public int remove() {
    ...
    temp = buffer[rear] = -1;
    rear--;
    size--;
    return temp;
} 

In producer, there is a print statement that prints 5 values that were added to the buffer (max size of buffer) but then nothing happens after that. Producer adds the values to the array and then enters the waiting state, but Consumer doesn't do anything since its still remains in the waiting state.

I can't figure out why Consumer doesn't continue despite Producer executing notify each time it adds something to the buffer.


Solution

  • In your code synchronized(this) is pointless as both Consumer and Producer are independent objects. Each of these objects has it's own this monitor which is not accessed by the other. You are stuck in Consumer on while(buffer.isEmpty()) wait(); because nothing in Producer calls cosumer.notify().

    Most likely it should be synchronized(buffer) (followed by buffer.wait() and buffer.notify()) as it's the buffer object that represents the shared state in your code.

    You are reimplementing a java.util.concurrent.ArrayBlockingQueue with your Buffer. Why not to use the class which is already available in the JDK?