Whether the wait queue revisits code inside a synchronized method

I read about thread synchronization and wait / notify constructs from the tutorial . It states that

When the wait is called, the thread releases the lock and suspends execution. At some other point, another thread will acquire the same lock and call Object.notifyAll, informing all threads waiting for this lock that something important has happened.

Some time after the second thread has released the lock, the first thread re-blocks and resumes, returning from the wait call.

AFAIK, if there are multiple threads that can compete for the lock, when the first thread wakes up notify

, any of them can acquire the right to lock on that object. My question is, if this first thread itself re-purchases the lock, does it need to start over from the beginning of the synchronized method (which means it executes the code again before the while () loop wait condition) or does it just pause on a line wait()

?

// Does the waiting thread come back here while trying to own the
// lock (competing with others)?
public synchronized notifyJoy() {
    // Some code  => Does this piece of code gets executed again then in case
    // waiting thread restarts its execution from the method after it is notified?
    while (!joy) {
        try {
            // Does the waiting thread stay here while trying to re-acquire
            // the lock?
            wait();
        } catch(InterruptedException e) {}
    }
    // Some other code
}

      

+3


source to share


2 answers


The method only completes when the thread it is executing has finished executing its execution method, regardless of whether it returns normally or has an exception that goes unmapped inside that method. The only way for your method not to execute until one of these things happens is for the JVM to be killed from under you, with java.lang.System.exit, or if this method is run on a daemon thread, the JVM turns off. There is nothing strange here. The awaited thread drops the lock and hibernates, but this does not stop the method from executing.

The thread awakened by his call to wait never left; all the time the thread was waiting, it was still in the sleep mode. Before it can leave the wait method, it must first acquire the lock it gave in order to start waiting. He then has to check all the conditions that need to be checked before he can know whether to keep waiting.

This is why the guarded blocks tutorial says that waits should be looped through:

A wait call does not return until another thread issues a notification that some special event may have occurred, although this is not necessarily an event that this thread is waiting for:



public synchronized void guardedJoy() {
    // This guard only loops once for each special event, which may not
    // be the event we're waiting for.
    while(!joy) {
        try {
            wait();
        } catch (InterruptedException e) {}
    }
    System.out.println("Joy and efficiency have been achieved!");
}

      

Note. Always call wait inside a loop that checks the wait state. Do not assume that the interrupt was for a specific condition that you expected, or that the condition is still true.

(The wording used in the tutorial is misleading, the word "interrupt" should be "notification." It's also a shame that the interrupt code shown below throws InterruptedException without setting the interrupt flag, it would be better to allow InterruptedException to be thrown from this method and not catch it at all.)

If the thread is "running", this loop is not needed, your code will start at the beginning of the method, acquire the lock, and check the condition in which it is waiting.

+6


source


Thread execution starts immediately after waiting for a call. It does not restart the block from the beginning. wait () can be roughly implemented similarly

public void wait() {
    release_monitor();
    wait_monitor();
    acquire_monitor();
}

      

This is not where it is actually implemented, this is just a rough idea of ​​what goes on behind the scenes. Each object has an associated monitor that can be fetched and released. Only one thread can hold the monitor at a time, and the thread can get the monitor recursively, no problem. Call to wait for an object Releases the monitor so that another thread can acquire it. The waiting thread then waits until it wakes up with a call to notify / notifyAll. On awakening, the waiting thread waits again for the object monitor request and returns to the calling code.



Example:

private Object LOCK = new Object;
private int num = 0;
public int get() {
    synchronized( LOCK ) {
        System.out.println( "Entering get block." );

        LOCK.wait();

        return num;
    }
}

public void set( int num ) {
    synchronized( LOCK ) {
        System.out.println( "Entering set block." );

        this.num = num;

        LOCK.notify();
     }
}

      

"Entering get block."

will only be printed once for each call get()

0


source







All Articles