它是否在调用后立即继续执行wait()
?它是否从服务方法的开头一直开始?
Stephen Hartley 的 Concurrent Programming: The Java Programming Language 中的一段话对此事有这样的说法,我不确定我是否完全理解:
这种通知方案不可能在同步的监控服务方法中间等待信号,然后在收到信号后在该点继续在监控服务方法内部执行。
它所指的通知方案是使用通知对象解决读写器问题的一种实现。
这是该解决方案的代码片段(我只显示与阅读器相关的方法):
private int numReaders = 0;
private boolean isWriting = false;
private Vector waitingReaders = new Vector();
private Vector waitingWriters = new Vector();
public void startRead(int i) {
Object convey = new Object();
synchronized (convey) {
if (cannotReadNow(convey))
try { convey.wait(); }
catch (InterruptedException e) {}
}
}
private synchronized boolean cannotReadNow(Object convey) {
boolean status;
if (isWriting || waitingWriters.size() > 0) {
waitingReaders.addElement(convey); status = true;
} else {
numReaders++; status = false;
}
return status;
}
public synchronized void endRead(int i) {
numReaders--;
if (numReaders == 0 && waitingWriters.size() > 0) {
synchronized (waitingWriters.elementAt(0)) {
waitingWriters.elementAt(0).notify();
}
waitingWriters.removeElementAt(0);
isWriting = true;
}
}
我如此困惑的原因是上面的引用似乎与同一本书的代码示例中显示的编程实践相矛盾。
例如,这是 Readers and Writers 解决方案的代码片段,使用普通监视器,没有通知对象
public synchronized void startRead(int i) {
long readerArrivalTime = 0;
if (numWaitingWriters > 0 || numWriters > 0) {
numWaitingWriters++;
readerArrivalTime = age();
while (readerArrivalTime >= startWritingReadersTime)
try {wait();}
catch (InterruptedException e) {}
numWaitingReaders--;
}
numReaders++;
}
如果线程不可能在被调用阻塞的地方继续执行wait()
,为什么要使用 while 循环来检查条件?如果每个被阻塞然后通过调用重新进入监视器的线程都startRead()
必须从该方法的开头开始,正如上面的引用似乎暗示的那样,if 语句是否足以检查条件?
此外,这如何解释下一个引用,在书中紧跟在上面的引用之后:
为避免死锁,线程在等待通知对象之前必须使用 return 语句离开同步方法。