I have a thread that's running in infinite loop executing some code, which will acquire a Lock.
Meanwhile I have another thread doing scheduled task that also need to acquire the lock to do something.
To ensure that the scheduled task won't be starved in case the lock is occupied by the infinite loop for too long, I let the thread sleep for a moment after unlocking. I think that's a reasonable move and not an overkill provided that I don't mind the performance cost with the sleep?
And a follow up question too: I see someone else doing the same, but instead of sleeping for a constant time, it's sleeping for a random time ThreadUtil.sleep(RandomUtil.nextInt(5, 100)), but I couldn't fathom the benefits of doing this.
private final Lock writeLock = new ReentrantLock(true);
while (true) {
writeLock.tryLock(100, TimeUnit.MILLISECONDS);
try {
doSomething();
} finally {
writeLock.unlock();
}
// food for everyone!
ThreadUtil.sleep(10);
}
Some points to clarify and a follow up question:
The scheduled task is acquiring the lock with a timeout (writeLock.tryLock(100, TimeUnit.MILLISECONDS)), identical to how the infinite-loop thread does it.
In addtion to the scheduled task, there's actually another use case to trigger a function manually (via ws call) and acquire the lock to do something.
The question: if the infinite loop thread does NOT sleep at all, I assume other threads will still eventually be executed, just that there might be a delay of uncertain amount of time?
At least for the scenario you described, I don't see any benefit of having random sleep time like ThreadUtil.sleep(RandomUtil.nextInt(5, 100)). Your ThreadUtil.sleep(10); will do the same job.
Only thing is I am not sure how you scheduled task thread is acquiring the lock. I think it will also have a loop which check every x ms (let's say 10 ms) whether the lock is released or not. As long as you have only two threads (one having the lock & another trying to acquire the lock), you should be fine. But let's say we have three threads. A thread has lock & B & C threads are doing loop to acquire the lock. If B thread always comes out & try before C thread & the lock is released by A thread at that interval, C thread will always starve. The sleep & release cycle will always happen only between A & B threads as the schedule is predictable. To make it unpredictable & make sure all three threads get the chance to acquire the lock, some randomness in the sleep time is necessary.
But I think there is a better solution than sleep & acquire. wait() & notifyAll() would be a better fit here. Thread A calls notify() on some object after specific interval & starts waiting for it. Thread B & C are already waiting on the same object. One of them will be notified & acquire the lock. Let's say C got the lock this time. If C doesn't have some scheduled task, it will again call notify() immediately. Then one of A or B would get the lock. Who acquires the lock will be decided by JVM & it will have better implementation so that one thread doesn't starve.
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.
I'm trying to get a better grasp on using sleep function calls in relation to mutex locks. If a mutex were to be held by one thread while the sleep from another thread expires, does control go back to the first thread immediately, or would the thread have to at least wait for the mutex being held to be released first before switching back to the other thread?
There is no relationship between Thread.sleep() and any kind of lock.
A call to Thread.sleep(nnn) returns after at least nnn milliseconds have elapesed (unless it throws an InterruptedException), and that's all a developer ever needs to know about it.
Pretty much all you need to know about mutexes (e.g., synchronized blocks), is that only one thread can lock the same instance at the same time time. A locked mutex becomes available to waiting threads as soon as the owner unlocks it. It has nothing to do with whether or not any of the threads is or was in a sleep() call.
sleep() maintains the lock but wait() does not,
my thinking on wait is that it releases the lock as to give other threads a chance to acquire the monitor on that thread while he is waiting.
but having doubt with sleep() why thread maintains the lock while sleeping as it always comes to the runnable state after sleeping
why thread maintains the lock while sleeping as it always comes to the runnable state after sleeping
Consider the below scenario:-
private Object objLock = new Object();
public void myMethod() {
....
synchronized(objLock) {
Thread.sleep(1000); // make the current running thread sleep for 1 second only.
... // Code here which needs to be executed immediately after 1 second sleep time
}
....
}
If at all JVM relesed lock when sleep was called in the above code then when it comes back to runnable state (resumption of execution will depend on scheduling and the availability of processors on which to execute the thread as per JLS Sleep ) your program may not resume at all if another thread by chance took a lock which would make the program behaviour inconsistent. This could be one of the reasons why it doesnot release any locks.
Thread.sleep doesn't have anything to do with locking.
Object.wait needs to be called when holding a lock because the test for the condition to stop waiting needs to be done while holding the lock, in order to have a consistent view of the condition. But usually a thread isn't holding a lock while sleeping.
Sleeping while holding a lock would seem like really bad behavior. But if you need multiple locks, where you acquire one, and have to back off before retrying getting the other, then sleeping while holding a lock might make sense. If calling sleep released locks, this kind of back-off tactic would not work.
Having Thread.sleep be oblivious to locks makes the API simpler and gives the programmer more options (by not totally ruling out its use by a thread that needs to hold onto a lock).
Q: What does Thread.sleep(n) do?
A: NOTHING. Absolutely nothing at all.
Q: How long does it take?
A: At least n milliseconds if the thread is not interrupted.
You don't need to know much else about Thread.sleep().
According to a colleague, JVM does not guarantee that when calling "notify" on an object, the correct "wait" will be notified at that time. He says there can be a case when a previous notify which is not valid anymore is delivered at an invalid time.
Is this true? If so, how/why is this, and what use is the wait/notify mechanism if you cannot assume something as basic as this will work?
For java.lang.Object.notify, The Javadoc says:
Wakes up a single thread that is waiting on this object's monitor. If
any threads are waiting on this object, one of them is chosen to be
awakened. The choice is arbitrary and occurs at the discretion of the
implementation. A thread waits on an object's monitor by calling one
of the wait methods.
Here is a pattern to wait for a particular condition:
synchronized( lock ) {
while( conditionEvaluation( data )) {
lock.wait();
}
}
The counterpart should use java.lang.Object.notifyAll() to ensure the vivacity of the application. Even if today, it's only one waiter, after many evolutions of the software, it may be several waiters in the future, so notifyAll() is more robust than notify().
Each object that waits on an intrinsic lock will enter the lock's wait set. When you invoke notify on the lock object, one of the threads in its wait set will be chosen to resume work. The only guarantee that the JVM offers is that the waiting threads will be eventually notified. One of the main reasons for this non-deterministic behavior is the way suspended threads are chosen to run by the JVM, which is arbitrary. In addition however, locks in java implement a non-fair locking policy which permits thread barging. This simply means that it is permissible for new lock requests to jump ahead of the lock's wait set, it the lock is available at the time of the request. The justification behind this is that given substantial contention, there might be some (potentially significant) delay before choosing and resuming a suspended thread in the wait set and the time it actually runs. Any incoming lock request from a thread could therefore utilize this time delay to immediately run, in the hope that it will have released the lock by the time the resumed thread is ready to run. For example consider the following sequence of events:
Thread A that previously has acquired monitor X calls notify()
Thread B waiting on monitor X has chosen to be suspended (arbitrarily).
Thread C tries to acquire monitor X, sees that it is available and acquires it.
Thread C runs (despite thread B is currently in the process of being resumed)
Thread C finishes execution and releases monitor X, just before thread B is actually run.
Thread B is ready to run so it acquires the lock and starts execution.
It should be evident that between step 2 and 6 there exists some time interval where no threads are actually using the lock. Thread C barges in and utilizes the time interval as an optimization. The downside of this of course is the risk of not releasing the lock at the time thread B is ready to run, which at that time thread B will notice that the lock is unavailable and will enter the wait set again. Statistically however it can be proven that non-fair locking offers better performance in most situations.
As an aside note, you could use fair locks where waiting threads are resumed in the order they acquired the lock, but in practice this offers worse performance. Read more about this here: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html
I hope this answers your question.
No it's not true. When a thread invokes notify, one waiting thread is awakened (if such a thread exists, otherwise notification is lost). Probably your colleague had in mind "spurious notify", which can awake a thread when in fact no other thread invoked notify or notifyAll. To filter "spurious notify", each notify invocation should accompanied with some change in monitored object state, and the waiting threads should check that state:
synchronized void up() {
counter++;
notify();
}
synchronized void down() {
while (counter==0) {
wait();
}
counter--;
}
Note checking state in down() is done before call to wait(), as it could be changed before the invocation and the notification is lost. In other words, the real information is passed with object's state, and wait/notify only help to avoid polling. Never rely on notifications without changing an object's state.
What is the ReentrantLock#tryLock(long,TimeUnit) implementation doing when it tries to aquire a lock ? Assume Thread A acually owns the Lock of myLock, and Thread B call myLock.tryLock(10,SECONDS), is Thread B sleeping or waiting ?
In other words, was is the difference of this 2 implementations:
1.
while (true)
try {
if (readLock.tryLock())
return;
MILLISECONDS.sleep(5);
}catch (InterruptedException e) {}
2.
while (true)
try {
if (readLock.tryLock(5,MILLISECONDS))
return;
}catch (InterruptedException e) {}
First of all, the second will wait less than 5 millis if lock released, because it doesn't need wait for wake up from the sleep. So, it's less exposed to starvation problem.
Then, j.u.c.l package uses LockSupport#park methods to pause a thread, not Thread.sleep. And as I understand it makes difference on the thread scheduler, the park allows lower latency, but not sure how exactly the sleep is implemented.
Also, your code doesn't make any sense, exactly the same effect could be achieved by lock() method.
It is waiting for the lock and the thread is asleep.
Internally, if the tryLock(long, TimeUnit) method fails to acquire the lock immediately, it waits for the amount of time specified. If the lock becomes available before this amount of time, it returns immediately with the lock. Note that in this case, when there are multiple threads requesting a lock, the ReentrantLock will randomly pick a thread to give the lock to next. This behavior can be changed by passing true to the fairness value in the constructor new ReentrantLock(true).
The second example will only check for the lock every five milliseconds. If the lock becomes available while it is sleeping and is given to another thread before it wakes up, this thread will be unavailable for acquiring the lock.
If you're using this code with many threads waiting for the lock, note that neither solution you have provided will guarantee that every thread will get the lock at some point. The second code can continue getting sniped by another thread just before the five milliseconds are up. The first code is random, but even with the fairness value set each thread will give up its place in line every five milliseconds. If this is the case you're better off increasing the timeout value. A good value would be about double the maximum amount of time that you would expect it to take for every thread to get a turn.
Technically there is no difference with respect to the state of the waiting thread. From the JavaDoc:
If the lock is held by another thread then the current thread becomes disabled
for thread scheduling purposes and lies dormant [...]
This is very similar to what happens in case of sleeping, but I guess we can't say for sure unless we know the implementation.
Now, note this part:
[...] lies dormant until one of three things happens:
The lock is acquired by the current thread; or [...]
That means that in case the lock becomes free in the meantime, it will acquire it and return. In the other case, while it is sleeping, the thread has no chance to get the lock even if it is free.
Another subtle difference that may appear between the two cases is the fact that the timed trylock is sensitive to the fairness policy of the ReentrantLock. That is:
If this lock has been set to use a fair ordering policy then an available lock
will not be acquired if any other threads are waiting for the lock.
The untimed trylock is known to be not fair and may succeed to acquire the lock even if other threads are already waiting on it.
I guess that the second one will wait for a 5 milliseconds to get a lock in difference with the first one which will try to lock immediately. So thread B will wait if in 5 ms (within 5ms) lock it doesn't get a lock it will return false. Normally there no difference if you have 5ms in your timeout but in case you increment this number you will get the clear image.
5ms is a timeout it will wait for 5ms for a lock that means if the lock is available after 3ms it will return after 3 ms with true.
For a great reference on how locks and other concurrency primitives are implemented see Shavit and Herlihy's excellent The Art of Multiprocessor Programming.