Search code examples
javamultithreadingproducer-consumer

Why Consumer thread is not able to remove messages from Vector?


I am trying to create a solution for Producer/ Consumer problem where one thread is putting message in Vector and another is removing from it.

import java.util.Vector;
public class Producer implements Runnable {
    static final int MAXQUEUE = 5;
    private Vector<String> messages;

    public Producer(Vector<String> messages) {
        super();
        this.messages = messages;
    }

    @Override
    public void run() {
        try {
            while (true) 
                putMessage();
        } catch (InterruptedException e) {
        }
    }

    private synchronized void putMessage() throws InterruptedException {
        while (messages.size() == MAXQUEUE) {
            wait();
        }
        messages.addElement(new java.util.Date().toString());
        System.out.println("put message");
        notifyAll();
    }

    public static void main(String args[]) {    
        Vector<String> messages = new Vector<String>();
        new Thread(new Producer(messages)).start();
        new Thread(new Consumer(messages)).start();
    }
}

class Consumer implements Runnable{
    public Consumer(Vector<String> messages) {
        super();
        this.messages = messages;
    }
    private Vector<String> messages;

    public synchronized String getMessage() throws InterruptedException {
        notifyAll();
        while (messages.size() == 0) {
            wait();//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep.
        }
        String message = (String) messages.firstElement();
        messages.removeElement(message);
        return message;
    }

    @Override
    public void run() {
        try {
            while (true) {
                String message = getMessage();
                System.out.println("Got message: " + message);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Whenever I am running the program, it is printing put message 5 times. I don't understand even after notifyAll(), it is not giving lock to consumer.


Solution

  • Your code is not working because your two threads are not notifying/waiting on the same monitor.

    They each notify and wait on their own monitor, not a shared monitor. Change code to use a shared monitor, e.g. messages, including the synchronizations.

    private void putMessage() throws InterruptedException {
        synchronized (messages) { // <======
            while (messages.size() == MAXQUEUE) {
                messages.wait();  // <======
            }
            messages.addElement(new java.util.Date().toString());
            System.out.println("put message");
            messages.notifyAll(); // <======
        }
    }
    
    public String getMessage() throws InterruptedException {
        synchronized (messages) { // <======
            while (messages.size() == 0) {
                messages.wait();  // <======
            }
            String message = (String) messages.firstElement();
            messages.removeElement(message);
            messages.notifyAll(); // <======
            return message;
        }
    }
    

    Notice that methods are no longer synchronized.