In the context of monitors, where does a blocked thread continue executing after being woken by a call to notify()?

35 views Asked by At

Does it continue executing immediately after where it called wait()? Does it start all the way from the beginning of the service method?

A passage from Stephen Hartley's Concurrent Programming: The Java Programming Language had this to say about the matter, which I'm not sure if I understand entirely:

It is not possible with this notification scheme to wait in the middle of a synchronized monitor service method for a signal and then continue executing inside the monitor service method at that point after receiving the signal.

The notification scheme it is referring to is an implementation of the solution to the Readers and Writers problem using notification objects.

Here is a snippet of code of that solution (I'm only showing methods related to Readers):

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;
    }
}

The reason I'm so confused is the quote above seems to contradict programming practices shown in code samples from the same book.

For example, this is a snippet of code of the Readers and Writers solution using plain monitors, without notification objects

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++;
}

If it's not possible for a thread to continue executing where it was blocked by a call to wait(), why is a while-loop used to check for the condition? If every thread that gets blocked and then regains entry to the monitor via a call to startRead() has to begin from the beginning of that method, as the quote above seems to be suggesting, wouldn't an if-statement suffice for checking the condition?

Moreover, how does any of this explain this next quote, which in the book follows immediately after the quote above:

To avoid deadlock, the thread must leave the synchronized method with a return statement before waiting inside the notification object.

1

There are 1 answers

0
Vladimir Parfenov On

If I understood this question... Try this:

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/notifyAll methods can be called only from synchronized(concreteObject) block. If you call their without concreteObject (just wait() or notify()), it's same as this.wait() or this.notify().

Synchronized non static methods are same as synchronized(this) blocks.