在await()返回后,Java Condition无法重新获取与其关联的锁(ReentrantLock)

时间:2013-07-24 03:47:53

标签: java locking conditional-statements

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class Foo {
    private ReentrantLock _lock;
    private Condition _cond;
    private Thread _thr;
    private LinkedList<String> _msgQueue;

    public Foo() {
        _lock = new ReentrantLock();
        _cond = _lock.newCondition();
        _msgQueue = new LinkedList<String>();
        startThread();
    }

    public void putMsg(String msg) throws Exception {
        _lock.lock();
        _msgQueue.addLast(msg);
        _cond.signal();
        System.out.println(Thread.currentThread().getId() + ": Signal write thread.");
        _lock.unlock();
        System.out.println(Thread.currentThread().getId() + ": Unlocked.");
    }

    private void startThread() {
        _thr = new Thread() {
            public void run() {
                _lock.lock();
                while(true) {
                    try {
                        while (!_msgQueue.isEmpty()) {
                            String msg = _msgQueue.getFirst();
                            System.out.println(msg);
                            _msgQueue.removeFirst();
                        }

                        System.out.println(Thread.currentThread().getId() + ": getHoldCount:" + _lock.getHoldCount());
                        System.out.println((Thread.currentThread().getId() + ": isLocked:" + _lock.isLocked()));
                        System.out.println(Thread.currentThread().getId() + ": isHeldByCurrentThread:" + _lock.isHeldByCurrentThread());
                        System.out.println(Thread.currentThread().getId() + ": Awaiting...");

                        _cond.await();

                        System.out.println(Thread.currentThread().getId() + ": Write thread awaken");

                    } catch (Exception e) {
                        e.printStackTrace();
                        break;
                    } finally {
                        try {
                            _lock.unlock();
                        } catch (Exception e) {
                        }
                    }
                }
                System.out.println("Write thread exit.");
            }
        };

        _thr.start();
    }
}

public class LockTest {
    public static void main(String[] args) throws Exception {
        Foo foo = new Foo();
        foo.putMsg("Msg 1");
        foo.putMsg("Msg 2");
        Thread.sleep(1000);
        foo.putMsg("Msg 3");
    }
}

The code output after one running:
1: Signal write thread.
1: Unlocked.
1: Signal write thread.
1: Unlocked.
Msg 1
Msg 2
8: getHoldCount:1
8: isLocked:true
8: isHeldByCurrentThread:true
8: Awaiting...
1: Signal write thread.
1: Unlocked.
8: Write thread awaken
Msg 3
8: getHoldCount:0
8: isLocked:false
8: isHeldByCurrentThread:false
8: Awaiting...
Write thread exit.
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.AbstractQueuedSynchronizer.fullyRelease(Unknown Source) at 

java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source) 

at Foo$1.run(LockTest.java:44)

问题是: 根据{{​​3}},当线程返回时,它保证保持此锁定。但是从输出中,我们看到await()返回后,它不会重新获取锁。这是一个错误还是我犯的一些错误?

1 个答案:

答案 0 :(得分:1)

  

根据http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#await(),当线程返回时,保证保持此锁定。

是的,但它也说线程必须在调用方法之前保持锁定:

  

当调用此方法时,假定当前线程保持与此Condition关联的锁。由实现来确定是否是这种情况,如果不是,如何响应。通常,将抛出异常(例如IllegalMonitorStateException),并且实现必须记录该事实。

这与“普通”监视器(Object#wait)的工作方式相同:您必须在开始等待时保持锁定(在Object#wait的情况下使用synchronized块,此处使用Lock #lock)。锁定将被释放,您等待。等待结束后,您还可以再次按住锁定。