Java多线程锁异常:IllegalMonitorStateException

在项目多线程编程中用了ReentrantLock配合Condition来控制线程的加锁和解锁:

private void signalAllConnect() {
        final ReentrantLock lock = this.connectLock;
        try {
            lock.lockInterruptibly();

        } catch (InterruptedException e) {
            SyncLogUtil.e(e);
        } finally {
            connectCondition.signalAll();
                SyncLogUtil.d("notify the connect task...");
                lock.unlock();
            }
    }

之前的代码是这么写的,采用lockInterruptibly()来上锁,结果随机性出现以下异常:

java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:123)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1235)
    at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:429)
    at com.xtc.sync.connection.TCPConnection.putConnectTaskToQueue(TCPConnection.java:435)
    at com.xtc.sync.connection.TCPConnection.connect(TCPConnection.java:410)
    at com.xtc.sync.connection.TCPConnection.connect(TCPConnection.java:339)
    at com.xtc.sync.connection.ConnectionService.connect(ConnectionService.java:288)
    at com.xtc.sync.connection.ConnectionService.decodeData(ConnectionService.java:414)
    at com.xtc.sync.connection.ConnectionService.access$1600(ConnectionService.java:52)
    at com.xtc.sync.connection.ConnectionService$5.onRead(ConnectionService.java:381)
    at com.xtc.sync.connection.ReadAndWriteDataThread.onRead(ReadAndWriteDataThread.java:156)
    at com.xtc.sync.connection.ReadAndWriteDataThread.run(ReadAndWriteDataThread.java:109)

意思是该线程还未被lock,然后就调用了unLock造成的异常,跟进源码里面发现异常是这边报出来的:

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

而getExclusiveOwnerThread()会在线程被lock的时候调用的,也就是说线程确实还没被上锁就被unLock了,因为我用的是lockInterruptibly(),所以在线程调用interrupt()的时候这里会抛出InterruptedException异常,然后线程lock就失败,但是后面的finally里面却有对线程执行了unLock,所以就报错了,解决方法如下:

private void signalAllConnect() {
        final ReentrantLock lock = this.connectLock;
        try {
            lock.lockInterruptibly();
            try {
                connectCondition.signalAll();
            } finally {
                SyncLogUtil.d("notify the connect task...");
                lock.unlock();
            }
        } catch (InterruptedException e) {
            SyncLogUtil.e(e);
        }
    }

改成如上写法,当lockInterruptibly()抛出异常的时候就不会执行unlock()方法了,而且我看了BlockQueue的一些阻塞实现也是类似如上写法,它从来不会把unLock操作和lockInterruptibly操作放在同一级,而是把unlock操作放在lockInterruptibly操作的下一步,保证lockInterruptibly()抛出异常后,不执行unlock

你可能感兴趣的:(java多线程)