【问题标题】:Thread behaviour on member variable lock成员变量锁上的线程行为
【发布时间】:2019-08-10 05:35:31
【问题描述】:

运行以下代码时,会抛出 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,这就是它的行为方式。

我已经通过使用 consumeItem() 方法创建一个单独的 Consumer 类来实现我想要的,该方法具有 synchronised(this) 代码和 ConsumerWaitNotify 以 Consumer 对象为成员。

但这有什么问题。我仍然很困惑,无法预测确切的行为。谁能帮帮我?

【问题讨论】:

    标签: java multithreading synchronization wait notify


    【解决方案1】:

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

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

    一个队列,它还支持在检索元素时等待队列变为非空,并在存储元素时等待队列中的空间可用。

    【讨论】:

    • 谢谢。我知道 Linked 和 Array Blocking Queue 使工作更容易,但只是为了理解等待和通知我写的。一个查询是,我假设由于代码 synchronized(queue) 是在对象 queue 上调用的,它会自动等待,即会有一个像 这样的隐式调用queue.wait()queue.notify()。我认为隐式调用仍然是 this.wait() ,即在 ConsumerWaitNotify 类的对象上。所以必须有明确的等待和通知调用。我说的对吗?
    • @Nizam 是的,synchronized 不会更改 waitnotify 方法的范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-13
    • 2017-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 2018-12-24
    相关资源
    最近更新 更多