Java并发编程 - java.lang.IllegalMonitorStateException

今天在实现阻塞队列时,代码抛出了 java.lang.IllegalMonitorStateException 异常。代码以下:java

public class BlockingQueue_1 {

    private final List<Object> queue = new LinkedList<>();
    private int capacity = 10;

    public BlockingQueue_1() {
    }

    public BlockingQueue_1(int capacity) {
        this.capacity = capacity;
    }

    public synchronized Object put(Object item) throws InterruptedException {
        while (queue.size() >= capacity) {
            wait();
        }
        queue.add(item);
        queue.notifyAll();
        return item;
    }

    public synchronized void remove() throws InterruptedException {
        while (0 == queue.size()) {
            wait();
        }
        queue.remove(0);
        queue.notifyAll();
    }

    public synchronized int getSize() {
        return queue.size();
    }
}

JavaDoc上关于IllegalMonitorStateException 的解释是:函数

Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.this

翻译过来就是:spa

抛出该异常代表,一个线程试图在一个对象的监视器上等待,或通知已经在对象的监视器上等待而不拥有指定监视器的其余线程。线程

咱们再来看 Object.notify() 这个函数的JavaDoc中有相关的解释:翻译

A thread becomes the owner of the object's monitor in one of three ways:
1. By executing a synchronized instance method of that object.
2. By executing the body of a synchronized statement that synchronizes on the object.
3. For objects of type Class, by executing a synchronized static method of that class. code

简单说就是在调用wait()或者notify()以前,必须使用synchronized语义绑定住被wait/notify的对象。对象

而上述代码若是给queue加锁,显而易见会出现死锁问题,因此最后我将代码改为了下面的形式。解决了问题。blog

public class BlockingQueue_2 {

    private final List<Object> queue = new LinkedList<>();
    private int capacity = 10;

    public BlockingQueue_2() {
    }

    public BlockingQueue_2(int capacity) {
        this.capacity = capacity;
    }

    public synchronized Object put(Object item) throws InterruptedException {
        while (queue.size() >= capacity) {
            wait();
        }
        queue.add(item);
        notifyAll();
        return item;
    }

    public synchronized void remove() throws InterruptedException {
        while (0 == queue.size()) {
            wait();
        }
        queue.remove(0);
        notifyAll();
    }

    public synchronized int getSize() {
        return queue.size();
    }
}

 

后来在网上看到另一段代码也会抛出相同异常:three

    private boolean wait = false;

    public boolean pleaseWait() {
        synchronized (this.wait) {
            if (this.wait == true) {
                return false;
            }

            this.wait = true;

            try {
                this.wait.wait();
            } catch (InterruptedException e) {

            }

            return true;
        }
    }

这里的问题在于 this.wait 这个变量是一个Boolean,而且在调用this.wait.wait()以前,this.wait执行了一次赋值操做:

this.wait = true;

Boolean型变量在执行赋值语句的时候,实际上是建立了一个新的对象。也就是说,在赋值语句的以前和以后,this.wait并非同一个对象。

synchronzied(this.wait)绑定的是旧的Boolean对象,而this.wait.wait()使用的是新的Boolean对象。因为新的Boolean对象并无使用synchronzied进行同步,因此系统抛出了IllegalMonitorStateException异常。

相关文章
相关标签/搜索