Concurrency: Condition.awaitNanos() not releasing lock - java

In my program i am using a Condition object created from a
private static final Lock lock = new ReentrantLock();
like so:
private static final Condition operationFinished = MyClass.lock.newCondition();
Occasionally (as it is always happening with concurrency problems) i encounter following behavior:
Thread1 aquires the lock
Thread1 calls operationFinished.awaitNanos() - this should suspend Thread1 and release the lock.
Thread2 tries to aquire the same lock, but debugging output shows that Thread1 is still holding the lock!
According to documentation this behavior is impossible, because upon awaitNanos() Thread1 first releases the lock and then suspends.
If it didn't release the lock, then it would not suspend, therefore Thread2 could never even get a possibility to try to get hold on the lock.
Has anybody experienced something similar? This errors happens once in 100 times - but still it indicates that I am either not using the concurrency-utilities in a proper way, or that there is some kind of bug in the java.utils.concurrent.* package (which i doubt).
UPDATE:
In response to Peters answer:
I observe following behavior: Apparently the 2 threads deadlock each other. I can see that Thread2 blocks (waiting for the lock) and at the same time awaitNanos() in Thread1 never times out.

Are you sure that the wait time hasn't finished? If you wait for a short period of time (a few hundred nanoseconds, for example), the wait time could expire before Thread2 can fully start, in which case Thread1 might be reactivated first.

Depending on how you are viewing this information, I have seen many examples of where multiple threads wait() on an object still say they are all holding the same lock. It may be that the stack trace or monitoring is mis-leading.
Say you have thread1 which is holding the lock, but in awaitNanos(), you have Thread2 which is trying to obtain the lock(), but sometimes Thread3 is holding the lock as well....
I would do a jstack -l {pid} to check all the threads which might be holding the lock.
If a lock deadlocks, awaitLock (nor wait()) won't return as it must acquire the lock before doing so. (Unless it is interrupted)

Related

how can deadlock occur if locks guarantee atomicity

Situation 1:
//snippet1
a=1
if(a!=0){
print(a);
}
//snippet2
a=0;
lets say thread T1 is executing snippet1, checks the if condition (which is true),enters the scope of if, then T1 is interrupted, and T2 executes snippet2, now T1 resumes and executes print(a). this is wrong as even though a is now 0, T1 goes ahead and prints despite the if condition being false.
The solution to the above problem that I read is acquire a lock on snippet1, then until the snippet1 is over, T1 won't be interrupted.
Good enough!
But I have a doubt regarding the following:
Situation 2:
//snippet3
acquire_lock1;
{
acquire_lock2;
}
//snippet4
acquire_lock2;
{
acquire_lock1;
}
Lets say thread T3 is executing snippet3 and T4 executing snippet4. Say T3 acquired lock1, was interrupted, T4 acquired lock2 and went on to acquire lock1, but it is now held by T3. So now this is a classic example of deadlock.
I am having problem in understanding that, if acquiring a lock guarantees atomicity of execution, and that once lock is acquired on the critical section, we cannot interrupt that thread, then how come after acquiring lock1 was T3 interrupted and T4 went on with the execution.
According to me, once lock1 is acquired by T3, it should begin execution without getting interrupted ,acquire Lock2, release lock2,release lock1, and complete this entire process without interruption. But this way a deadlock shall never occur.
Can anyone explain me whats wrong with this thought process, and when exactly can a deadlock occur?
Thanks in advance!
As #Kayaman said already in there comment: "Acquiring a lock doesn't mean that the thread can't be interrupted".
The lock just protects ("guards") a code section from being executed by two threads at the same time (or that another thread may enter that section before another thread has left it). Technically, an acquired lock only guarantees that no other thread can acquire the same lock at the same time. This means that such another thread waits in the acquire statement until the lock is released (or a timeout expires, or hell freezes over … – for the following discussion, these details are not required).
So when Thread1 acquires Lock1 at the beginning of Section1, and then dies without returning the lock, no other thread may enter Section1. Or when Thread1 will be interrupted while holding the lock, it has to get back control to be able to release the lock before any other thread may enter Section1.
Your second scenario is now prone to a deadlock:
Thread1 acquires Lock1 when entering Section1_1, guarded by this lock
Thread2 acquires Lock2, guarding Section2_1,
Thread1 advances to the begin of Section1_2 that is guarded by Lock2
The attempt by Thread1 to acquire Lock2 fails, because this is already hold by Thread2
Thread1 now waits that Lock2 is released
Meanwhile Thread2 advanced to the begin of Section2_2 that is guarded by Lock1
As Lock1 is already hold by Thread1, the attempt by Thread2 to acquire that lock fails
Now Thread2 wait for Lock1 to be released
As both threads are now mutually waiting for the other one to release the thread, your program is trapped in a deadlock
An easy way to prevent that is to ensure that locks are always taken in the same sequence (also known as the 'ABC' rule): when threads need the locks Lock_One, Lock_Two, Lock_Three, they have to acquire them always in the sequence of their names (first Lock_One, then Lock_Three, finally Lock_Two). Although this seems not logical (because of the chosen names …) it guarantees that you do not get a dead lock. A thread can acquire Lock_Three only if it has already acquired Lock_One, or it does not need Lock_One at all; same for Lock_Two …
If for some reason it is required to acquire Lock_Two before Lock_Three … rename the locks so that the ABC rule will work again – and adjust your code afterwards!

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.

Confusion with wait and Sleep method of thread

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().

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

Java threads internals

I have been studying internals of Java for quite some time. I am curious to learn and understand how threading/locking takes place in Java.
So, in order to access a synchronized method or a synchronized block, the thread has to acquire the lock on the object first. So, now, here is what I need a bit more light.
So, whenever the thread acquires the lock on the object, does it increment the value of the semaphore internally?
If the answer is yes then let's take a look at this scenario.
class ABC{
public void method_1(){
synchronized(xyz){
....
}
}
public void method_2(){
...
synchronized(xyz){
....
}
}
}
So, say there are two threads: Threaad 1 and Thread 2. Assuming, Thread1 entered method_1 first and therefore acquired a lock on xyz first. And, say now, Thread2 enters method_2 and tries to acquire lock on xyz. What will happen?
(Acc to me, Thread2 will get blocked since it finds that the object's semaphore value>0)
Let me know if my reasoning is correct.
whenever the thread acquires the lock on the object, does it increment the value of the semaphore internally?
Implementation specific, but unlikely, Since every lock can be obtained only once, there is no need for a counter. A simple toggle will do. I assume that every lock holds a reference to the Thread that owns it (or null).
Update: Actually, it is quite a bit more complex than that. The lock also needs to maintain a list of threads that are waiting for it. Also, a thread can temporarily release a lock via the wait/notify mechanism (so there will be an entry counter after all). On top of that, lock management has a big impact on performance, so that there are all kinds of optimizations going on. I found this interesting blog by someone who is working on JVM locking.
So, say there are two threads: Threaad 1 and Thread 2. Assuming, Thread1 entered method_1 first and therefore acquired a lock on xyz first. And, say now, Thread2 enters method_2 and tries to acquire lock on xyz. What will happen?
Yes, Thread 2 will be blocked, and wait until it can eventually obtain the lock.
Your reasoning is roughly correct. Thread 2 will be blocked, and will remain blocked until (at least) Thread1 releases the mutex.
However, the lock is generally not implemented using a conventional semaphore with a simple counter. Typically there is a single lock bit that only gets "inflated" into a full lock if the object is locked reentrantly (e.g. if Thread1 tries to lock xyz while it already holds the lock on that object) or when there is contention for the lock (e.g. when Thread2 tries to lock xyz while Thread1 has it locked).
But you don't need to concern yourself with the implementation details of Java locks ... unless you are implementing a JVM yourself!
The other answers have pretty much answered your question, but for further reading I recommend:
Java Concurrency In Practice

Categories

Resources