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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章