java 为什么我会收到 IllegalMonitorStateException?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16884061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:15:59  来源:igfitidea点击:

Why am I getting IllegalMonitorStateException?

javamultithreadingthread-safety

提问by Kelsey Abreu

I get the following Exception being thrown when I try to unlock an object.

当我尝试解锁一个对象时,我收到以下异常。

Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
    at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
    at Pipe.unlock(Pipe.java:21)
    at Station.doWork(Station.java:81)
    at Station.run(Station.java:66)
    at java.lang.Thread.run(Unknown Source)

All that Pipe.unlock is doing is the following:

Pipe.unlock 所做的一切如下:

public void unlock(){
   accessLock.unlock();
}

Where accessLock is an ReentrantLock

其中 accessLock 是 ReentrantLock

Do you know where the issue could be?

你知道问题出在哪里吗?

EDIT:

编辑:

This is the run method in Station

这是Station中的run方法

if(Pipes[inConnection].accessLock.tryLock()){
    System.out.println("Station "+ StationNumber+": granted access to pipe "+inConnection+".");

//This is just a way for me to keep track if both pipes have been granted
            if(connected<0)
                connected=inConnection;
            else
                connected+=inConnection;
}


if(Pipes[outConnection].accessLock.tryLock()){
            System.out.println("Station "+ StationNumber+": granted access to pipe "+outConnection+".");

    //This is just a way for me to keep track if both pipes have been granted
    if(connected<0)
        connected=outConnection;
    else
        connected+=outConnection;   
}


        doWork();

While this is the doWork method:

虽然这是 doWork 方法:

private void doWork() {
    if(connected==inConnection+outConnection){
        System.out.println("Station "+StationNumber+": successfully flows "+inConnection+".");
        System.out.println("Station "+StationNumber+": successfully flows "+outConnection+".");

        Pipes[inConnection].unlock();
        System.out.println("Station "+StationNumber+": released access to pipe "+inConnection+".");

        Pipes[outConnection].unlock();
        System.out.println("Station "+StationNumber+": released access to pipe "+outConnection+".");

        try {
            Thread.sleep(rand.nextInt(200));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        WorkLoad--;
    }else if(connected >=0 ){
        Pipes[connected].unlock();
        System.out.println("Station "+StationNumber+": released access to pipe "+connected);

    }

    connected=-1;
}

回答by xor_eq

I know this question is more than a year old, but I was facing the same problem and the solution turned out to be not another Thread that was holding the Lock somehow but basically a very simple mistake and the inner details of a ReentrantLock. If we look at the implementation of tryRelease:

我知道这个问题已经有一年多了,但我遇到了同样的问题,结果证明不是另一个以某种方式持有锁的线程,而是一个非常简单的错误和 ReentrantLock 的内部细节。如果我们看一下 tryRelease 的实现:

protected final boolean tryRelease(int releases) {
  int c = getState() - releases;
  if (Thread.currentThread() != getExclusiveOwnerThread())
     throw new IllegalMonitorStateException();
  ..
  if (c == 0) {
    ..
    setExclusiveOwnerThread(null);
  }
  ..
}

If the release-count drops to zero, the exclusiveOwnerThread is set to null. And if you afterwards try to release the lock once more, you're not the exclusiveOwnerThread anymore, since your Thread is unlikely to be null. So one simple .unlock() too much can lead to this (in this situation rather confusing) Exception.

如果发布计数降为零,则exclusiveOwnerThread 设置为空。如果您之后再次尝试释放锁,您就不再是exclusiveOwnerThread,因为您的Thread 不太可能为空。所以一个简单的 .unlock() 太多会导致这个(在这种情况下相当混乱)异常。

回答by Jon Skeet

The documentationis pretty clear:

文档是相当清楚的:

If the current thread is the holder of this lock then the hold count is decremented. If the hold count is now zero then the lock is released. If the current thread is not the holder of this lock then IllegalMonitorStateExceptionis thrown.

如果当前线程是此锁的持有者,则持有计数递减。如果保持计数现在为零,则释放锁。如果当前线程不是此锁的持有者,IllegalMonitorStateException则抛出。

So the thread which is trying to unlock isn't the holder of the lock. We can't tell why you expectedit to be the same thread without seeing more of your code.

所以试图解锁的线程不是锁的持有者。如果没有看到更多代码,我们无法说出为什么您希望它是同一个线程。