成员变量锁上的线程行为

时间:2019-03-19 16:02:09

标签: java multithreading synchronization wait notify

运行以下代码时,它将引发IllegalMonitorStateException。

class Consumer {
    private int capacity = 5;
    private Queue<Integer> queue = new PriorityQueue<Integer>(capacity);

    class ConsumerWaitNotify implements Runnable {
        public void run() {
            try {
                consumeItem();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();

            }
        }
        void consumeItem() {
            try {
                synchronized (queue) {            //Line 1
                    while(queue.size() == 0) {
                        System.out.format("%n%s: Waiting..Empty Queue, Size: %d%n", Thread.currentThread().getName(),
                                            queue.size());
                        wait();           //Line 2
                    }
                    int popItem = queue.poll();
                    System.out.format("%n%s: Consumes Item: %d, Size: %d", Thread.currentThread().getName(), 
                                        popItem, queue.size());
                    notify();
                }           
            } catch(InterruptedException e) {
                e.printStackTrace();

            }
        }
    }
}

public class ConsWaitNotify {

    public static void main(String[] args) {
        Consumer pc = new Consumer();
        Consumer.ConsumerWaitNotify cwn = pc.new ConsumerWaitNotify();
        Thread consumer = new Thread(cwn, "CONSUMER");
        consumer.start();

    }
}

以下是错误:

CONSUMER: Waiting..Empty Queue, Size: 0
Exception in thread "CONSUMER" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:485)
    at com.threadconcurrency.lock.prodcons.Consumer$ConsumerWaitNotify.consumeItem(ConsWaitNotify.java:67)
    at com.threadconcurrency.lock.prodcons.Consumer$ConsumerWaitNotify.run(ConsWaitNotify.java:52)
    at java.lang.Thread.run(Thread.java:619)

在调试过程中,我发现执行第2行(即wait()命令)后,线程转而退出可运行状态,它跳到第1行执行,并执行了两次。因此,它将引发异常。

我假设是在 wait 之后,线程可能释放了对象锁定( queue ),但仍然持有类 ConsumerWaitNotify ,这就是为什么它会那样表现。

我通过使用具有 synchronized(this)代码和 consumeItem()方法制作了一个单独的 Consumer 类,实现了我想要的目标em> ConsumerWaitNotify ,以Consumer对象为成员。

但是这有什么问题。我仍然很困惑,无法预测确切的行为。有人可以帮我吗?

1 个答案:

答案 0 :(得分:1)

您正在同步变量queue,但在wait()对象上调用notify()this。您要么需要用synchornized(this)来保持锁,要么调用queue.wait()queue.notify()以确保您通知拥有该锁的监视器。您可以看看Guarded Blocks docs

请注意,您不需要自己实现队列。 JDK提供了一些java.util.concurrent.BlockingQueue实现:

  

一个队列,它另外支持以下操作:在检索元素时等待队列变为非空,并在存储元素时等待队列中的空间变为可用。