This question already has answers here:
Can notify wake up the same thread multiple times?
(4 answers)
Closed 9 years ago.
What happens if you notify a lock, and immediately notify that lock again? Assume there are 2 or more threads waiting on that lock. Is it guaranteed that two threads are woken up? Or is it possible that only one threads is woken up, meaning that the second notification becomes obsolete?
lock.notify();
lock.notify();
Thanks!
Assume there are 2 or more threads waiting on that lock. Is it guaranteed that two threads are woken up?
Yes. Each notify takes a thread from the waiting queue and puts it in the blocked queue -- the awoken thread must first get access to the synchronized lock in question. If there is only 1 thread waiting on the lock then the 2nd notify() would do nothing.
It is important to realize that the thread will not start executing immediately. Since it had to be in a synchronized block on lock to be able to do the wait() it must get access to the lock again before it can run. There may be multiple other threads already in the block queue, waiting to get access to lock.
I suspect the behavior would be similar to calling notifyAll() (in this case it's more like a notifyTwo())
The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
Related
From the JAVA docs for Object notify()
The awakened thread will not be able to proceed until the current
thread relinquishes the lock on this object.
This means that unless the Thread which notifes, its synchronized block is complete and it releases the lock, the waiting thread cannot proceed. If that's the case then whats the point of having notify() if the sync block is going to be executed anyway? What's the actual use of notify() if it doesn't wake up the waiting thread and let it do its job?
Good question. Will point you to take a look at the Thread State Class.
A thread that calls the Object.notify method enables a thread that previously called Object.wait is now enabled to be scheduled by the thread scheduler. In parlance, the thread that was waiting is now "runnable". Although it is "runnable", it is not "running".
It can only continue running when the thread invoking notify releases the lock - one way is when it exits out of the synchronized block.
There are a lot of schematics on the web on the Thread States. Some of them are completely incorrect or confusing since they introduce terminology not in the official docs. Here is one that makes sense to me.
Strictly speaking, we don't: we could have the waiting thread run a loop where it re-acquires the lock, checks the condition, and sleeps for a short amount of time. But using wait() and notify() is much more efficient, because then the waiting thread doesn't keep waking up and tying up CPU (and tying up the lock).
notify() and notifyAll() are used to wake up thread(s) that called wait() on the same object on which notify() or notifyAll() is called.
Without call to notify() those "waiting" threads will wait forever (although JVM spec says that threads may sometime wake up without call to notify).
Also because call to notify() doesn't releases the lock associated with the object itself that call usually is the last statement in a synchronized block.
So notify() is used together with wait() and not by itself.
Usually the use case is like the following (blocking queue with limited size).
Method that adds element to queue (some pseudo code)
synchronized(lockObject) {
if (size < LIMIT) {
addElement();
lockObject.notifyAll(); //notifying threads that are waiting to get element from empty queue
} else {
lockObject.wait(); // waiting for other thread to get element from queue and make room for new element
}
}
Method that gets element
synchronized(lockObject) {
if (size > 0) {
getElement();
lockObject.notifyAll(); // notify threads that there is a room for new element
} else {
lockObject.wait(); // waiting for other thread to put element into the queue
}
}
Also calling lockObject.wait() releases lock on lockObject. More details regarding that could be found here: Java : Does wait() release lock from synchronized block
Notifying is what wakes up a thread that is waiting. If you remove the notify then waiting threads stay waiting (barring spurious wakeups but let’s not go there for now).
(Interrupting wakes up the thread but the guidance is to use it for cancellation only. Interruption targets a specific thread, where notifying lets the scheduler decide which threads are affected.)
When a thread calls wait it has to have the lock, then the wait method lets go of the lock.
When a thread calls notify it has to have the lock.
As a practical matter the notify can’t take effect on any waiting thread until the notifying thread relinquishes the lock. The first thing the notified thread is going to need to do anyway is to try to acquire the lock. All the passage you're quoting is trying to say is that the wakeup doesn't occur instantaneously when a thread calls notify.
So what happens here is that the notifying thread lets go of the lock and sends the notify to the scheduler, the scheduler decides which thread to notify, then the notified thread wakes up and contends for the lock in order to leave the wait method.
Imagine if you need a thread to wait for another thread to do something that it may or may not even currently be actively working on. For example, a thread that's waiting for a job to do may need to wait until another thread has put a job on the list of jobs it should do if that list is empty. How would you do this?
You can't just use some form of mutual exclusion. There may be long periods of time when there's no work to do and not thread holds any lock on the queue. There may just not be any work to do right now. The thread that does work needs to wait, without holding any lock, until another thread has given it some work to do.
So somewhere, there's a thread that does something like this:
Acquire the lock that protects some shared state that another thread might be waiting for a change to. (In this case, the job queue.)
Change the shared state to reflect the fact that the thing a thread might need to wait for has happened. (That is, put a job on the queue.)
Release the lock and let any waiting thread(s) know that the thing has happened.
So what could our code to wait look like? Perhaps:
Acquire the lock that protects the shared state.
Check whether we need to wait or not. (Is there a job on the queue?)
If we need to wait, wait. (If not, wait for a job to be placed on the queue.)
...
Oops, we have a problem. The thing we're waiting for can't happen because we hold the lock. No other thread can change the shared state. (Our thread to put a job on the queue can't touch the queue until we release the lock we acquired in step 1.)
Let's try it again:
Acquire the lock that protects the shared state.
Check whether we need to wait or not. (Is there a job on the queue?)
If we don't need to wait, exit this algorithm. (If there's a job, take it off the queue, release the lock, and do it.)
Release the lock. (So another thread can put a job on the queue.)
Wait for the thing to happen.
...
Oops, we have another problem. What if the thing we're waiting for happens after step 4 but before step 5. Since the lock has been released, the thing we're waiting for can happen. We can't check again because we don't hold the lock. How can we ensure we don't wait for something that has already happened, which may mean waiting forever?
To solve this, we need an atomic "unlock and wait" operation. That's what wait does. And we also need some operation that can end this wait that can be called by the thread that changed the shared state so that we no longer need to wait. That's what notify does.
Suppose in multi-threaded environment there are 5 threads t1,t2,t3,t4,t5.... Thread t1,t2,t3,t4 calls the wait() method (inside synchronized block) and only Thread t5 calls notify() method then which thread going to get priority to again acquire the lock in critical section.
The choice is arbitrary and any one of the 4 threads may be woken up. The intrinsic lock in java is not fair which will cause some of the waiting threads to wait longer than others even though they attempted to gain the lock first. A ReentrantLock can be used to grant access to the longest waiting thread if this matters for your program.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
In Java if a thread, t2, attempts to attain a lock, from synchronized, which is currently in use by another thread, t1, then t2 will switch from runnable to blocked. Correct? What about with ReentrantLocks?
If the thread t1 finishes using the lock, does t2 then automatically switch back to runnable or do you need to use notifyAll()? What about with ReentrantLock usage without a condition. If you aren't using a condition how do you inform the thread t2 that it should switch back to runnable? Is it ever wise, or even possible to use reentrant locks without a condition?
If this question has already been answered (I couldn't find it), I would be grateful if you would link it to me.
It sounds like you're confusing the blocked and waiting states. Blocked means that the thread is trying to acquire the lock and can't so is stuck. Waiting means the thread is dormant; it's hanging out until it receives a notification, or until it otherwise comes back from waiting (timeout, if called with a timeout value, or spurious wakeup).
Once a lock becomes available the OS scheduler has to decide which blocked thread gets it. The thread it picks to get the lock becomes runnable.
So notify pertains to waiting threads, not blocked ones. A thread that has the lock but which has figured out it can't progress (it detects the condition it's waiting for isn't true) can call wait on that lock, releasing the lock and going dormant. You use notify to tell the scheduler to wake up any one thread that is waiting on the lock. Once the thread is woken up it has to reacquire the lock it previously released before it can exit the wait method.
The basic behavior of ReentrantLock is analogous to intrinsic locks, except that you can have multiple conditions with reentrant locks. Keep in mind ReentrantLock has its own separate methods to call (await and signal instead of wait and notify). You would use conditions with ReentrantLock when you want the threads to wait and get notified, with different conditions used so that threads will be waiting only on conditions relevant to them.
If a thread t2 attempts to synchronize on a lock that is currently in use by another thread t1 - for example by attempting to enter a synchronized block when t1 is already in a synchronized block on the same lock - then t2 will block, yes. This is also true for reentrant locks, including the ReentrantLock class; it should be noted that default locks are reentrant in Java (more on this later).
If t1 releases a default lock, such as by exiting the synchronized block, then t2 is unblocked; this is a feature of the language. However, if you are using a ReentrantLock, the thread holding the lock must explicitly call ReentrantLock.unlock() to release the lock, just as it must have called ReentrantLock.lock() to obtain the lock.
Note that "reentrant" refers to whether a single thread can "reenter" synchronized blocks, not to any interaction between threads. Reentrant locks can be locked again by threads that already hold the lock; nonreentrant locks cannot. Note that in Java, if a single thread obtains a reentrant lock more than once, it must release the lock the same number of times before other threads waiting for the lock are unblocked. For default locks, this happens naturally with nested synchronized blocks, possibly at different function call levels.
Say I have three threads, thread 1, thread 2, and thread 3 all sharing the same lock. Thread 2 acquires the lock, does some work and then blocks via a call to the await method. Thread 1 then acquires the lock, does some work, and during the middle of it, thread 3 tries to acquire the lock but is blocked since thread 1 is holding it. Thread 1 finishes working and, before terminating, signals thread 2 that it can reacquire the lock. So what happens then? Will thread 2 or thread 3 acquire the lock next?
Thank you so much for your time and help in advance.
If no priority is given, whoever comes first will acquire the lock.
While mutual exclusion may provide safety property, it does not ensure liveness property. There can be cases where a thread keeps coming first to acquire the lock, resulting in starvation (other threads wait forever because someone keeps occupying).
Google with the keywords highlighted will help you understand more. I found these slides really comprehensive http://www.cs.cornell.edu/Courses/cs414/2004su/slides/05_schedule.pdf
If you're using a ReentrantLock (or any of its subclasses), you can pass a "fairness" flag to the constructor. If set to true, this will ensure that control of the lock passes to the longest-waiting thread, in this case your Thread 1.
Lock lock = new ReentrantLock(true);
Suppose d is the object we're using to invoke wait. When a thread invokes d.wait, it must own the intrinsic lock for d — otherwise an error is thrown. Invoking wait inside a synchronized method is a simple way to acquire the intrinsic lock.
so is this means that two threads cannot invoke wait() at the same time? what do intrinsic lock here mean [mentioned it as Monitor]? but how 's monitor implemented to achive mutual exclusion?
once the thread invokes wait does it holds object forever?
if so how about other thread using that lock for notifyAll()?
if we need to acquire object during notifyall, then why all waiting threads notified?
shouldn't it notify threads waiting on that object alone?
Any code to explain is appreciated.
so is this means that two threads cannot invoke wait() at the same
time?
Correct two thread cannot invoke wait() at the same time. However, once one thread is in wait(), another thread can acquire the same lock and enter a wait() state soon after. You can have any number of threads WAITING on the same object, but only one really holds the lock.
what do intrinsic lock here mean [mentioned it as Monitor]? but
how 's monitor implemented to achive mutual exclusion?
Only one thread can be running while holding a object. Other thread can be blocking trying to acquire the lock and more can be wait()ing on it.
once the thread invokes wait does it holds object forever?
The opposite, it gives it up or another thread can acquire it almost immediately.
if so how
about other thread using that lock for notifyAll()?
If you call notifyAll() on the object, all the wait()ing thread are woken in turn. Those threads can only acquire the lock one at a time and will re-acquire the lock as soonas they can.
if we need to acquire object during notifyall, then why all waiting
threads notified?
That is what notifyAll does, it is considered safer than using notify, which wakes a random one as it is less prone to coding errors.
shouldn't it notify threads waiting on that object alone?
That is what it does.
You should note that;
before you notify()/notifyAll() you should perform a state change. You should also wait() inside a loop which checks that state change. You need to do this because a) wait() can miss a notify(), b) it can wake spuriously c) another thread might grab whatever you ahve done and it might need to wait again.
over the last 9 years, there has been greater use of High Level concurrency classes. Using these classes mean you don't need to work with Threads, Queues, wait() and notify() directly.
Invoking wait inside a synchronized method is a simple way to acquire
the intrinsic lock.
Wait does not provide the lock on an object rather it makes the thread to wait to listen about the lock release when other thread calls notify. Thread gets the lock when it enters the guarded//synchronized block. Synchronzied block/method allows to take the lock if available otherwise thread cannot enter those code block.
Locks are not held forever, according to the javadoc:
The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
When you call wait(), you release the intrinsic lock on that object, until another thread calls notify() or notifyAll() on it. At that point, the JVM will wake one of the threads waiting, and automatically reacquire the lock on that object.
So to answer your question, yes, multiple threads can wait() on the same object.