Java实现的生产者消费者问题出现java.lang.IllegalMonitorStateException错误

6
import java.util.LinkedList;
import java.util.Queue;

class Producer extends PubSub implements Runnable{

    @Override
    public void run() {
        synchronized(queue){
            if (queue.size() == 99){
                try { 
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.add(2);
            try{
                Thread.sleep(1000);
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            notify();
            }
        }       
}


class Consumer extends PubSub implements Runnable{

    @Override
    public void run() {
        synchronized(queue){
            if(queue.isEmpty()){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }   
            }
            System.out.println(queue.poll());
        }

    }

}
public class PubSub {
    static Integer QUEUE_SIZE = 100;
    Queue<Integer> queue = new LinkedList<Integer>();
    public static void main(String[] args) {
        Producer producer = new Producer();
        Consumer consumer = new Consumer();
        Thread producerThread = new Thread(producer);
        Thread consumerThread = new Thread(consumer);
        producerThread.start();
        consumerThread.start();
        System.out.println("Started both the threads");
    }

}

我在 wait() 部分遇到了 java.lang.IllegalMonitorStateException 异常。我想知道这里我做错了什么。有任何想法吗?
完整的异常如下所示。
Exception in thread "Thread-1" Started both the threads
java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at Consumer.run(PubSub.java:36)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at Producer.run(PubSub.java:23)
    at java.lang.Thread.run(Thread.java:745)

2
请提供完整的堆栈跟踪。 - Jens
1
Added in the question. - station
4个回答

6
您正在调用wait(),它等同于this.wait(),但是您没有持有this的监视器。您持有queue上的监视器。因此应该是queue.wait()。(对于notify()也是一样的)。

我一直在进行一些测试...成员“queue”不必是静态的才能被生产者和消费者共享吗? - RubioRic

3

请查看IllegalMonitorStateException的Javadoc文档。

https://docs.oracle.com/javase/7/docs/api/java/lang/IllegalMonitorStateException.html

当你试图在一个你没有持有监视器的对象上调用wait()(或notify())时,会抛出该异常;你已经在队列上同步了,但尝试在this上调用wait(),这不是队列,而是可运行对象。 将wait()改为queue.wait(),将notify()改为queue.notify()应该可以解决问题。

2
我认为你让代码正常工作了...根据JB Nizet所述,你必须在queue对象上调用wait和notify。我认为这样的对象必须被声明为static,以便由生产者和消费者共享。我已经包含了while循环,以便代码可以一直运行到时间结束。此外,在生产者和消费者第一次wait之前需要一个额外的notify。以下是包含这些更改的代码:
import java.util.LinkedList;
import java.util.Queue;

class Producer extends PubSub implements Runnable{

    @Override
    public void run() {
         int index = 0;

         while (true) {
            synchronized(queue){
                while (queue.size() == QUEUE_SIZE){
                    try {
                        System.out.println("Producer waits");
                        queue.notify();
                        queue.wait();
                    } catch (InterruptedException e) {
                       e.printStackTrace();
                    }
                }

                System.out.println("Produce element " + (++index));
                queue.add(2);
                queue.notify();

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }


            }
        }
    }
}


class Consumer extends PubSub implements Runnable{

     @Override
     public void run() {
         while (true) {
             synchronized(queue) {

                while (queue.isEmpty()){
                    try {
                         System.out.println("Consumer waits");
                         queue.notify();
                         queue.wait();
                    } catch (InterruptedException e) {
                         e.printStackTrace();
                    }
                }

                System.out.println("Consume element " + queue.poll());
                queue.notify();

            }
         }

     }

  }

public class PubSub {
     static Integer QUEUE_SIZE = 100;

     static Queue<Integer> queue = new LinkedList<Integer>();

     public static void main(String[] args) {
          Producer producer = new Producer();
          Consumer consumer = new Consumer();

          Thread producerThread = new Thread(producer);
          Thread consumerThread = new Thread(consumer);

          producerThread.start();
          consumerThread.start();

          System.out.println("Started both the threads");
     }

 }

enter image description here


消费者部分不起作用。消费者线程最初启动并等待。生产者生产了所有元素,但消费者没有接收。 - station
你确定你已经复制了所有的更改吗?我刚刚再次运行它,它可以正常工作。 - RubioRic

0
一个线程只能在已经获取锁的对象上调用notify()或wait()。在您的程序中,线程已经获取了队列对象的锁,然后在该对象上调用了wait()。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接