它是否在调用wait()
后立即继续执行?它是否从服务方法的开头一直开始?
Stephen Hartley的《并发编程:Java编程语言》中的一段话对这个问题有这样的说法,我不确定我是否完全理解:
使用此通知方案,不可能在同步监视服务方法的中间等待信号,然后在接收到信号后继续在监视服务方法中执行。
它所引用的通知方案是使用通知对象解决读取器和编写器问题的解决方案的实现。
以下是该解决方案的代码片段(我只显示与阅读器相关的方法):
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;
}
}
我如此困惑的原因是上面的引用似乎与同一本书的代码示例中显示的编程实践相矛盾。
例如,这是使用普通监视器的读取器和写入器解决方案的代码片段,没有通知对象
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-loop 来检查条件?如果每个被阻塞的线程,然后通过调用startRead()
重新获得对监视器的入口,都必须从该方法的开头开始,正如上面的引用所暗示的那样,if 语句是否足以检查条件?
此外,这些如何解释下一句话,在书中紧跟在上面的引文之后:
为了避免死锁,线程必须在通知对象内部等待之前,将同步方法保留为 return 语句。
如果我理解这个问题...试试这个:
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++;
}
public synchronized void endRead(int i) {
numReaders--;
if (numReaders == 0 && waitingWriters.size() > 0) {
notify();
waitingWriters.removeElementAt(0);
isWriting = true;
}
}
concreteObject.wait/notify/notify所有方法只能从syncd(concreteObject)块调用。如果你调用它们而不使用 concreteObject(只需 wait() 或 notify()),它与 this.wait() 或 this.notify() 相同。
同步的非静态方法与同步(this)块相同。