Signalling threads in a lock's condition - java

I have taken the following points from this API and I would like to know the difference between the 2 following points:
Waiting threads are signalled in FIFO order.
The ordering of lock reacquisition for threads returning from
waiting methods is the same as for threads initially acquiring the
lock, which is in the default case not specified, but for fair locks
favors those threads that have been waiting the longest.
It is related to Condition class which is usually returned by the ReentrantLock method .newCondition(), and the bit I quoted it's explaining the difference between the methods of Condition and the regular monitor methods of the Object class.
"Waiting threads are signalled in FIFO order". I think that as long as a lock is created either fair or not, the fact that the waiting threads are signalled in a FIFO order is totally irrelevant isn'it? because anyhow it's whether they have been constructed, fair or not, which decides how they are queued.
Just asking for a confirmation.
Thanks in advance.

Please see below answers to your questions:
1.Waiting threads are signalled in FIFO order.
When we invoke await() method of Condition, thread goes into waiting state, the above statement refers to how these threads in waiting state are signalled. So if threads T1 went to waiting state before T2, T1 will be signalled before T2.
2.The ordering of lock reacquisition for threads returning from waiting methods is the same as for threads initially acquiring the lock, which is in the default case not specified, but for fair locks favors those threads that have been waiting the longest.
In continuation to above statement, when waiting thread is signalled, it tend to reaquire lock. Though above statement says T1 will be signalled before T2, but when it comes to reaquiring lock, the order of reacquisition uses concepts defined by Lock. So, it depends on how Lock object was created. While creating Lock you might have specified a fairness parameter:
ReentrantLock(boolean fair)
If yes then that parameter is used, if not then default behaviour of locks happens, you can read more on ReentrantLock Locks at this link
There could be more explanations to these statements, just tried to best detail my understanding here. Hoping was able to clarify.
Cheers !!

As long as a lock is created either fair or not, the fact that the waiting threads are signaled in a FIFO order is totally irrelevant, isn't it? Because anyhow it's whether they have been constructed, fair or not, which decides how they are queued.
I think it is relevant.
Consider a scenario where T1 and T2 are waiting on a condition C (with T1 waiting longer than T2), T3 is running inside the monitor and T4 is waiting for its initial lock acquisition. T3 signals C and leaves the monitor releasing the lock. Let's suppose no spurious wakeup occur.
If the lock is fair, T4 will definitely acquire the lock before T1, but the fact that waiting threads are signaled in FIFO order will guarantee you that T1 will acquire the lock before T2.
Also, if the lock is not fair, we can't say which thread will acquire the lock first between T1 and T4, but again the fact that waiting threads are signaled in FIFO order guarantees that T1 will acquire the lock before T2, provided no other signals occur until T1 acquires the lock (for example in case T1 is responsible for the next signaling).

I think the source code can give us more clues about how it works.ReentrantLock.newCondition() return a ConditionObject in AbstractQueuedSynchronizer.Here is the source code link AQS source code.
1.Waiting threads are signalled in FIFO order.
There are two queues in AbstractQueuedSynchronizer.
One is for waiting for the lock(just call it lock waiting queue),you will see two volatile variable head and tail in
AbstractQueuedSynchronizer's class definition,and the fairness parameter will affect this queue's behavior.When you new a fair ReentrantLock and call acquire,AQS will call FairSync's tryAcquire to check if current thread is the first thread waiting in the lock waiting queue,see hasQueuedPredecessors.
Another queue is the signal queue in the definition of ConditionObject,you will see two variable firstWaiter and lastWaiter.When await is called,a node will add to the tail of the queue and When signal is called,a node from the head will be dequeued and add to the lock waiting queue to reacquire the lock.Add to the lock waiting queue didn't mean it will be woke up,but a Lock.unlock() will be called after signal,which will wake up the waiters,see unparkSuccessor.
2.The ordering of lock reacquisition for threads returning from waiting methods is the same as for threads initially acquiring the lock, which is in the default case not specified, but for fair locks favors those threads that have been waiting the longest.
wake up from the await method didn't mean to hold the lock,it will call acquireQueued to reacquire the lock and could be parked again.
In my understanding,the order of initially acquiring the lock is the same as the order of calling await,so the same as the order of calling acquireQueued,What confused me was but for fair locks favors those threads that have been waiting the longest.,When wake up from the await,in my opinion,it will be the first thread in the lock waiting queue,When call acquireQueued and check p == head && tryAcquire(arg),lock fair or not has no effect.
Hope this helps and let me if I am wrong.

Related

Is signal guaranteed to reach thread?

Lets say I have three threads, T1, T2, T3, a Lock lock and some Condition cond on a Resource resource.
T1 acquires lock and now does cond.await() due to some condition and T2 gets that lock and does cond.signal() and then proceeds to do lock.unlock(), but for a while, T3 was also trying to acquire the lock so it is at the line of lock.lock(), what exactly happens?
Does T2 re-get the lock or does T3 get it or is it random based on scheudler?
If you read the documentation, i.e. the javadoc of ReentrantLock, it specifically answers this question in the 3rd paragraph:
The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order.
Whenever a signal is issued one of the waiting threads will be removed and will be put back in entry set so that he can get a chance to run. In terms of signalAll all the waiting threads will be removed from the wait set and put back in entry set so that they get chance to run.
And yes the scheduler then decides which thread to pick from the entry set. In terms of fairness longest waiting will get the chance first.
Good explanation here

ReentrantLock fairness parameter

This question is full theoretical, I'm sorry but I cannot avoid this time.
I'm learning about ReentrantLock and read this:
Note however, that fairness of locks does not guarantee fairness of thread scheduling.
What does this mean? How can I imagine this?
Let's suppose that the lock is not held by anyone right now:
thread scheduler wakes up t1 thread (who is not the longest waiting thread)
t1 tries to acquire the lock
lock rejects t1 because t1 is not the longest waiting thread
t1 goes to sleep
thread scheduler wakes up a thread
Does Java work this way? In a very unsuccesful case this would mean lots of context switching (that leads to poor throughput, that is written down in the documentation).
What does this mean?
The OS will schedule the thread to run whenever it likes.
How can I imagine this?
The OS has little idea what the JVM would like to run next.
Does Java work this way?
Yes, Java doesn't control the OS scheduler.
What does this mean?
This means that a thread holding lock may continue holding the lock as long as it wants and can reacquire the same lock many time in succession and the longest waiting thread will keep waiting until current thread releases the lock.
So, fairness guarantee comes to play only when lock is free and java thread scheduler has to decide which thread the lock should be given to. And it is given to longest waiting thread(in case of synchronized, it's random).
It also means that the thread holding the lock is not being scheduled frequently and other threads are given more CPU time, so this thread is not able to complete and thus not releasing the lock.

Can another thread enter a monitor, while the waiting one is notified?

I am investigating Java concurrency and I've found one interesting question which I cannot answer.
For example, I have three threads: ThreadA, ThreadB and ThreadC. ThreadA enters the monitor, and invokes method wait(). Then ThreadB enters the same monitor, invokes method notify() and continue owning the monitor during some period of time. While ThreadB is owning the monitor, ThreadC tries to acquire the monitor too. My question is whether ThreadC can acquire the monitor earlier then ThreadA when ThreadB release it or not? If it can, why? Which conditions should be followed to reproduce it?
As per the Javadoc on Object.notify():
The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
So there exists the possibility that ThreadC owns the monitor before ThreadA. There is no defined order in which any of the threads enter/obtain the monitor, nor is there any priority or fairness mechanism in place for standard synchronization. All it really guarantees is that for a given lock object, only on thread will be in the synchronized block at once.
Given this fact, careful design considerations should go into how threads obtain the lock and for how long. A thread that repeatedly attempts to acquire a lock (acquire and then release but then acquire again) can cause another thread to be locked out indefinitely (called thread starvation).
Using ReentrantLock with a fairness policy can partially overcome this issue at some performance cost (its slightly slower than traditional synchronization).

Java Locks and Conditions

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

using Intrinsic Locks in SYNCHRONIZATION

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.

Categories

Resources