尽管调用notifyAll的线程拥有监视器,但为什么仍引发IllegalMonitorStateException?

时间:2018-11-17 15:24:20

标签: java multithreading

我试图深入了解wait()和notify()的概念。 为此,我编写了一个非常简单的程序,其中:

  1. 有一个共享的字符串'commonResource'
  2. 生产者应在此字符串中发布一些值
  3. 使用者应等待,直到此字符串中实际有可用值为止

这是代码:

package com.company; 

public class Wait {

    public static void main(String[] args) throws InterruptedException {
        Resource resource = new Resource();

        Thread consumerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    resource.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread producerThread = new Thread() {
            @Override
            public void run() {
                try {
                    resource.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        producerThread.start();
        consumerThread.start();
    }
}

class Resource {

    String commonResource = new String();

    public void consume() throws InterruptedException {
        System.out.println("In consume. Outside Sync block: " + Thread.currentThread().getName());
        synchronized (commonResource) {
            System.out.println("In consume. Inside Sync block" + Thread.currentThread().getName());
            commonResource.wait();
            System.out.println(commonResource);
        }
    }

    public void produce() throws InterruptedException {
        System.out.println("In Produce. Outside Sync block: " + Thread.currentThread().getName());
        // So that consumer executes first
        Thread.sleep(1000L);
        synchronized (commonResource) {
            System.out.println("In produce. Inside sync block: " + Thread.currentThread().getName());
            commonResource = "I am not empty now";
            System.out.println("Done production. I am now freeing up the resource");
            commonResource.notifyAll();
        }
    }
}

执行后,出现以下异常,代码挂起:

In consume. Outside Sync block: Thread-0
In consume. Inside Sync blockThread-0
In Produce. Outside Sync block: Thread-1
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)
    at com.company.Resource.produce(Wait.java:55)
    at com.company.Wait$2.run(Wait.java:23)
In produce. Inside sync block: Thread-1
Done production. I am now freeing up the resource

根据notifyAll的Java文档,执行notifyAll()时,监视器与其他线程一起运行。 但是从日志中以及根据我的理解可以看出,{-1}是{-1}的监视器的所有者,也是线程1在notifyAll()上调用的。

所以,我的问题是,为什么在这种情况下会抛出IllegalMonitorStateException? 我在了解这一点上缺少什么吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

正如@JBNizet所说,您更改了用作锁定的String值。这就是为什么您得到IllegalMonitorStateException的原因。要摆脱这种情况,可以像这样对final使用单独的Objectsynchronization

class Resource {
    private final Object lock = new Object();
    String commonResource = new String();

    public void consume() throws InterruptedException {
        System.out.println("In consume. Outside Sync block: " + Thread.currentThread().getName());
        synchronized (lock) {
            System.out.println("In consume. Inside Sync block" + Thread.currentThread().getName());
            lock.wait();
            System.out.println(commonResource);
        }
    }

    public void produce() throws InterruptedException {
        System.out.println("In Produce. Outside Sync block: " + Thread.currentThread().getName());
        // So that consumer executes first
        Thread.sleep(1000L);
        synchronized (lock) {
            System.out.println("In produce. Inside sync block: " + Thread.currentThread().getName());
            commonResource = "I am not empty now";
            System.out.println("Done production. I am now freeing up the resource");
            lock.notifyAll();
        }
    }
}