为什么我收到IllegalMonitorStateException?

时间:2013-06-02 15:09:44

标签: java multithreading thread-safety

当我尝试解锁对象时,我会抛出以下异常。

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)

Pipe.unlock所做的就是以下内容:

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

其中accessLock是ReentrantLock

你知道问题出在哪里吗?

编辑:

这是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();

虽然这是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;
}

2 个答案:

答案 0 :(得分:10)

我知道这个问题已经超过一年了,但我遇到了同样的问题,解决方案原来并不是另一个以某种方式持有Lock的线程,但基本上是一个非常简单的错误和ReentrantLock的内部细节。如果我们看一下tryRelease的实现:

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

如果release-count降为零,则将exclusiveOwnerThread设置为null。如果你之后尝试再次释放锁,那么你不再是exclusiveOwnerThread了,因为你的Thread不太可能是null。所以一个简单的.unlock()太多会导致这种情况(在这种情况下相当混乱)异常。

答案 1 :(得分:6)

documentation非常明确:

  

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

所以试图解锁的线程不是锁的持有者。我们无法告诉你为什么期望它是同一个线程而没有看到更多的代码。