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()返回后,它不会重新获取锁。这是一个错误还是我犯的一些错误?
答案 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)。锁定将被释放,您等待。等待结束后,您还可以再次按住锁定。