简体   繁体   中英

How can we use notifyAll to ensure that only one thread continues after wakeup?

From Programming Language Pragmatics , by Scott

To resume a thread that is suspended on a given object, some other thread must execute the predefined method notify from within a synchronized statement or method that refers to the same object. Like wait, notify has no arguments. In response to a notify call, the language run-time system picks an arbitrary thread suspended on the object and makes it runnable. If there are no such threads, then the notify is a no-op. As in Mesa, it may sometimes be appropriate to awaken all threads waiting in a given object; Java provides a built-in notifyAll method for this purpose.

If threads are waiting for more than one condition (ie, if their waits are embedded in dissimilar loops), there is no guarantee that the “right” thread will awaken. To ensure that an appropriate thread does wake up, the programmer may choose to use notifyAll instead of notify. To ensure that only one thread continues after wakeup , the first thread to discover that its condition has been satisfied must modify the state of the object in such a way that other awakened threads, when they get to run, will simply go back to sleep. Unfortunately, since all waiting threads will end up reevaluating their conditions every time one of them can run, this “solution” to the multiple-condition problem can be quite expensive.

  • When using notifyAll , all the awaken threads will contend to reacquire the lock, but only one can reacquire the lock, then return from wait() and then reevaluate the condition. So why does it say that " all waiting threads will end up reevaluating their conditions every time one of them can run"?

  • How does the thread, which reacquires the lock and rechecks that the condition become true, "modify the state of the object in such a way that other awakened threads, when they get to run, will simply go back to sleep"?

Thanks.

So why does it say that "all waiting threads will end up reevaluating their conditions every time one of them can run"?

After it will reacquire and release the lock a different thread will aquire it and run. This will continue until they all do that.

How does the thread, which reacquires the lock and rechecks that the condition become true, "modify the state of the object in such a way that other awakened threads, when they get to run, will simply go back to sleep"?

All the threads will have something like:

while (condition) {
    wait();
}

The notifyAll() caller will set condition to false before calling it and then the awakened thread will exit the while loop and before it returns and releases it will do:

condition = true;

All the other threads will awaken, check the condition, stay in the while loop and call wait() (go back to sleep).

Additionally, you should use explicit locking mechanism because it allows you to have multiple conditions and condition queues for a single lock, which will enable you to use signal() instead of signalAll() . And that has better performance and less contention.

Condition API

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM