Search code examples
javamultithreadingproducer-consumer

A question about Producer-Consumer Model in Java


I write a Java program to solve Producer Consumer problem in Multi-Threads. But it can not work correctly. The program:

public class ConsumerAndProducer {
static int  products = 0;
static int capacity = 10;
public static void main(String[] args) {
    new Thread(new Producer()).start();
    new Thread(new Consumer()).start();
}
static class Consumer implements Runnable{

    public void consume() {
        synchronized (ConsumerAndProducer.class){
            if(products <= 0){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            products--;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Consumer, remain:" + products);
            if(products == 9){
                notify();
            }
        }
    }

    @Override
    public void run() {
        while(true){
            consume();
        }
    }
}
static class Producer implements Runnable{

    public void produce() {
        synchronized (ConsumerAndProducer.class){
            if(products == capacity){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            products++;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Producer, remain:" + products);
            if(products == 1){
                notify();
            }
        }
    }

    @Override
    public void run() {
        while(true){
            produce();
        }
    }
}

And the errors:

Producer, remain:1
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at zhousai.ConsumerAndProducer$Producer.produce(ConsumerAndProducer.java:69)
    at zhousai.ConsumerAndProducer$Producer.run(ConsumerAndProducer.java:77)
    at java.lang.Thread.run(Thread.java:748)
Consumer, remain:0
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at zhousai.ConsumerAndProducer$Consumer.consume(ConsumerAndProducer.java:22)
    at zhousai.ConsumerAndProducer$Consumer.run(ConsumerAndProducer.java:43)
    at java.lang.Thread.run(Thread.java:748)

Solution

  • When I ran your code, I got the following error:

    Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner
    

    The line of your code throwing that exception is the call to method wait().
    You are calling method wait() of class Producer but you are synchronizing on ConsumerAndProducer.class. The wait() method must be called on the object that you are synchronizing on, because that object owns the lock and you must call wait() on the object that owns the lock. Hence the error message: current thread not owner.

    The simplest solution is to change your code such that you call ConsumerAndProducer.class.wait() rather than just wait().

    Here is your code with my suggested fix:

    public class ConsumerAndProducer {
        static int  products = 0;
        static int capacity = 10;
        public static void main(String[] args) {
            new Thread(new Producer()).start();
            new Thread(new Consumer()).start();
        }
    
        static class Consumer implements Runnable {
            public void consume() {
                synchronized (ConsumerAndProducer.class){
                    if (products <= 0) {
                        try {
                            ConsumerAndProducer.class.wait(); // change here
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    products--;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Consumer, remain:" + products);
                    if(products == 9){
                        ConsumerAndProducer.class.notify(); // change here
                    }
                }
            }
    
            @Override
            public void run() {
                while(true){
                    consume();
                }
            }
        }
    
        static class Producer implements Runnable{
            public void produce() {
                synchronized (ConsumerAndProducer.class){
                    if (products == capacity) {
                        try {
                            ConsumerAndProducer.class.wait(); // change here
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    products++;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Producer, remain:" + products);
                    if(products == 1){
                        ConsumerAndProducer.class.notify(); // change here
                    }
                }
            }
    
            @Override
            public void run() {
                while(true){
                    produce();
                }
            }
        }
    }