I was studying reentrant locking in Java. Need certain clarification on this concept that how actually it works. What all I understand for below snippet :
class Test{
public synchronized a(){
some code;
b();
some code;
}
public synchronized b(){
some code;
}
}
Above code has this scenario of reentrant lock issue.
What I understand here is, suppose we had Two Threads: T1 and T2 in application executing on Test shared object.
Whoever T1 or T2 acquires lock acquire on both a() and b(). Let say T1 first and executing a(). While execution of a() control reaches to b(); call. Now in that case T1 expecting a new Lock for this b(), or since it already had lock over b() so locking is skipped.
Need help with detailed explanation of this behavior along with issue in above code . Also how reentrant locking mechanism will help here along with snippet and detailed explanation for that as well.
A reentrant lock is one that allows a thread to acquire the lock again (many times) when it already holds the lock.
For example, if thread T1 calls a() on an object, the a() method acquires the lock on the object, and starts executing the body. When the body of a calls b(), the b() call "reentrantly" acquires the same lock. When the b() call returns, the a() call is still holding the lock. The lock is only released when the a() call returns.
(Hypothetically, if Java primitive locks were not reentrant, then the sequence T1 calls a() which then calls b() would probably either deadlock, or throw an exception ...)
Reentrant locks are typically implemented with a reference count which tells the locking implementation how deep the reentrancy is.
See also: https://stackoverflow.com/a/16504266/139985
If the lock wasn't re-entrant, the thread wouldn't be able to call b() while holding the lock it acquired when entering a().
When a() is called, and it call b() you need a lock which is reentrant or the thread will live lock itself try to acquire the lock a second time. Instead of trying to get the lock again, it instead recognises it already has a lock increments a counter so that when b() exists, it doesn't release the lock but instead decrements the counter.
Related
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Since an intrinsic lock is held by a thread, doesn't it mean that a thread run once equals an invocation basis?
Thank you, it seems mean that: in a thread,if I get a lock lockA when process function doA which call function doB, and doB also need a lock lockA,then there wil be a reentrancy. In Java, this phenomenon is acquired per thread, so I needn't consider deadlocks?
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
That is a misleading definition. It is true (sort of), but it misses the real point.
Reentrancy means (in general CS / IT terminology) that you do something, and while you are still doing it, you do it again. In the case of locks it means you do something like this on a single thread:
Acquire a lock on "foo".
Do something
Acquire a lock on "foo". Note that we haven't released the lock that we previously acquired.
...
Release lock on "foo"
...
Release lock on "foo"
With a reentrant lock / locking mechanism, the attempt to acquire the same lock will succeed, and will increment an internal counter belonging to the lock. The lock will only be released when the current holder of the lock has released it twice.
Here's a example in Java using primitive object locks / monitors ... which are reentrant:
Object lock = new Object();
...
synchronized (lock) {
...
doSomething(lock, ...)
...
}
public void doSomething(Object lock, ...) {
synchronized (lock) {
...
}
}
The alternative to reentrant is non-reentrant locking, where it would be an error for a thread to attempt to acquire a lock that it already holds.
The advantage of using reentrant locks is that you don't have to worry about the possibility of failing due to accidentally acquiring a lock that you already hold. The downside is that you can't assume that nothing you call will change the state of the variables that the lock is designed to protect. However, that's not usually a problem. Locks are generally used to protect against concurrent state changes made by other threads.
So I needn't consider deadlocks?
Yes you do.
A thread won't deadlock against itself (if the lock is reentrant). However, you could get a deadlock if there are other threads that might have a lock on the object you are trying to lock.
Imagine something like this:
function A():
lock (X)
B()
unlock (X)
function B():
A()
Now we call A. The following happens:
We enter A, locking X
We enter B
We enter A again, locking X again
Since we never exited the first invocation of A, X is still locked. This is called re-entrance - while function A has not yet returned, function A is called again. If A relies on some global, static state, this can cause a 're-entrance bug', where before the static state is cleaned up from the function's exit, the function is run again, and the half computed values collide with the start of the second call.
In this case, we run into a lock we are already holding. If the lock is re-entrance aware, it will realize we are the same thread holding the lock already and let us through. Otherwise, it will deadlock forever - it will be waiting for a lock it already holds.
In java, lock and synchronized are re-entrance aware - if a lock is held by a thread, and the thread tries to re-acquire the same lock, it is allowed. So if we wrote the above pseudocode in Java, it would not deadlock.
Java concurrency in practice book states - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain what it exactly means. First of all Intrinsic locks are reentrant by nature. The way reentrancy is achieved is by maintaining a counter for number of locks acquired and owner of the lock. If the count is 0 and no owner is associated to it, means lock is not held by any thread. When a thread acquires the lock, JVM records the owner and sets the counter to 1.If same thread tries to acquire the lock again, the counter is incremented. And when the owning thread exits synchronized block, the counter is decremented. When count reaches 0 again, lock is released.
A simple example would be -
public class Test {
public synchronized void performTest() {
//...
}
}
public class CustomTest extends Test {
public synchronized void performTest() {
//...
super.performTest();
}
}
without reentrancy there would be a deadlock.
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain this with an example.
class ReentrantTester {
public synchronized void methodA() {
System.out.println("Now I am inside methodA()");
methodB();
}
public synchronized void methodB() {
System.out.println("Now I am inside methodB()");
}
public static void main(String [] args) {
ReentrantTester rt = new ReentrantTester();
rt.methodA();
}
}
The out put is :
Now I am inside methodA()
Now I am inside methodB()
As in the above code, the ReentrantTester contains two synchronized methods: methodA() & methodB()
The first synchronized method methodA() calls the other synchronized method methodB().
When execution enters the methodA(), the current thread acquires the monitor for the ReentrantTester object.
Now when methodA() calls methodB(), because methodB() is also synchronized, the thread attempts to acquire the
same monitor again. Because Java supports reentrant monitors, this works. The current thread acquire the ReentrantTester's
monitor again and continue the execution of both methodA() and methodB().
The Java runtime allows a thread to reacquire a monitor that it already holds, because Java monitors are
reentrant. These reentrant monitors are important because they eliminate the possibility of a single thread
deadlocking itself on a monitor that it already holds.
This just means once a thread has a lock it may enter the locked section of code as many times as it needs to. So if you have a synchronized section of code such as a method, only the thread which attained the lock can call that method, but can call that method as many times as it wants, including any other code held by the same lock. This is important if you have one method that calls another method, and both are synchronized by the same lock. If this wasn't the case the. The second method call would block. It would also apply to recursive method calls.
public void methodA()
{
// other code
synchronized(this)
{
methodB();
}
}
public void methodB()
{
// other code
syncrhonized(this)
{
// it can still enter this code
}
}
it's about recurse, think about:
private lock = new ReentrantLock();
public void method() {
lock.lock();
method();
}
If the lock is not re-entrant able, the thread could block itself.
Immagine that I have Class First with several synchronised methods. When a thread locks the class First, does it lock per method or per class? For example does deadlock happen for the following code?
public class DeadLockQuestion {
public static class First{
public synchronized void a(){
}
public synchronized void b(){
}
public synchronized void c(){
}
public synchronized void d(){
}
public synchronized void e(){
}
}
public static void main(String... args){
First f = new First();
//This code is run in Thread 1
f.a();
// End
//This code is run in Thread 2 simultanously
f.b();
//End
// We have also Threads 3 & 4 & 5 that invoke c,d and e simultanously
}
}
You have got two locks in Java. One is Object lock. and the other is Class Lock.
The object lock locks access to synchronized non-static functions only. and Class lock locks on synchronized static functions only.
For you, its an object lock on object f. So all the synchronized non-static functions are locked for object f.
Since all the Threads are using the same object f, Only one Thread will be able to access your non-static functions a(), b(),... at a time.
Read more here
does deadlock happen for the following code?
No, it won't happen in your case. Because While one Thread is holding the lock, Other threads can't get inside your synchronized function.DeadLock happens due to resources.
You have only one resource thats Object f. There's no point of a dead-lock here because the class First doesn't lock another object and no cyclic lock can happen. Deadlock requires a cyclic lock!
Some Info:
Synchronization in java guarantees that no two threads can execute a
synchronized method which requires same lock simultaneously or
concurrently.
synchronized keyword can be used only with methods and code blocks.
These methods or blocks can be static or non-static both.
When ever a thread enters into java synchronized method or block it
acquires a lock and whenever it leaves java synchronized method or
block it releases the lock. Lock is released even if thread leaves
synchronized method after completion or due to any Error or
Exception.
It’s possible that both static synchronized and non static
synchronized method can run simultaneously or concurrently because
they lock on different object.
Useful Source Here, and here
Deadlock happens to threads, not to methods or classes.
The deadlocked threads also hold locks, but in this case it is impossible to tell which locks because you do not demonstrate an actual deadlock scenario (if two threads call synchronized methods of f one goes through and the other waits; deadlock requires at least two locks).
To lock each method independently use a synchronized block within each method and lock on a different object.
If you have an appropriate (and it should be final to prevent potential problems) object already within the class you can use that. If not create a private final Object aLock = new Object(); and then lock on that, for example:
private final Object aLock = new Object();
public void a() {
synchronized(aLock) {
// Do stuff that needs the lock
}
// do stuff that doesn't need the lock
}
Always hold the lock for as long as you need it, but no longer.
When a() is a synchronized method, f.a() literally means:
synchronized(f){
f.a();
}
So in this case a lock would happen for object monitor f. In your case you would require a second object to create a deadlock, I don't think it's possible to create a deadlock with a single object monitor. A typical deadlock pattern is when an order of lock acquisition is not being maintained, i.e. when this happens in two different threads:
synchronized(a){
synchronized(b){
...
}
}
// and
synchronized(b){
synchronized(a){
...
}
}
Firstly, Deadlock occurs with threads and not classes or methods.
Deadlock occurs when there is a cyclic dependency of locks.
Thread A ---> locks L1 ---> tries to lock L2
Thread B ----> locks L2 ------> tries to lock L1
Image source: FusionReactor deadlock plugin
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Since an intrinsic lock is held by a thread, doesn't it mean that a thread run once equals an invocation basis?
Thank you, it seems mean that: in a thread,if I get a lock lockA when process function doA which call function doB, and doB also need a lock lockA,then there wil be a reentrancy. In Java, this phenomenon is acquired per thread, so I needn't consider deadlocks?
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
That is a misleading definition. It is true (sort of), but it misses the real point.
Reentrancy means (in general CS / IT terminology) that you do something, and while you are still doing it, you do it again. In the case of locks it means you do something like this on a single thread:
Acquire a lock on "foo".
Do something
Acquire a lock on "foo". Note that we haven't released the lock that we previously acquired.
...
Release lock on "foo"
...
Release lock on "foo"
With a reentrant lock / locking mechanism, the attempt to acquire the same lock will succeed, and will increment an internal counter belonging to the lock. The lock will only be released when the current holder of the lock has released it twice.
Here's a example in Java using primitive object locks / monitors ... which are reentrant:
Object lock = new Object();
...
synchronized (lock) {
...
doSomething(lock, ...)
...
}
public void doSomething(Object lock, ...) {
synchronized (lock) {
...
}
}
The alternative to reentrant is non-reentrant locking, where it would be an error for a thread to attempt to acquire a lock that it already holds.
The advantage of using reentrant locks is that you don't have to worry about the possibility of failing due to accidentally acquiring a lock that you already hold. The downside is that you can't assume that nothing you call will change the state of the variables that the lock is designed to protect. However, that's not usually a problem. Locks are generally used to protect against concurrent state changes made by other threads.
So I needn't consider deadlocks?
Yes you do.
A thread won't deadlock against itself (if the lock is reentrant). However, you could get a deadlock if there are other threads that might have a lock on the object you are trying to lock.
Imagine something like this:
function A():
lock (X)
B()
unlock (X)
function B():
A()
Now we call A. The following happens:
We enter A, locking X
We enter B
We enter A again, locking X again
Since we never exited the first invocation of A, X is still locked. This is called re-entrance - while function A has not yet returned, function A is called again. If A relies on some global, static state, this can cause a 're-entrance bug', where before the static state is cleaned up from the function's exit, the function is run again, and the half computed values collide with the start of the second call.
In this case, we run into a lock we are already holding. If the lock is re-entrance aware, it will realize we are the same thread holding the lock already and let us through. Otherwise, it will deadlock forever - it will be waiting for a lock it already holds.
In java, lock and synchronized are re-entrance aware - if a lock is held by a thread, and the thread tries to re-acquire the same lock, it is allowed. So if we wrote the above pseudocode in Java, it would not deadlock.
Java concurrency in practice book states - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain what it exactly means. First of all Intrinsic locks are reentrant by nature. The way reentrancy is achieved is by maintaining a counter for number of locks acquired and owner of the lock. If the count is 0 and no owner is associated to it, means lock is not held by any thread. When a thread acquires the lock, JVM records the owner and sets the counter to 1.If same thread tries to acquire the lock again, the counter is incremented. And when the owning thread exits synchronized block, the counter is decremented. When count reaches 0 again, lock is released.
A simple example would be -
public class Test {
public synchronized void performTest() {
//...
}
}
public class CustomTest extends Test {
public synchronized void performTest() {
//...
super.performTest();
}
}
without reentrancy there would be a deadlock.
Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.
Let me explain this with an example.
class ReentrantTester {
public synchronized void methodA() {
System.out.println("Now I am inside methodA()");
methodB();
}
public synchronized void methodB() {
System.out.println("Now I am inside methodB()");
}
public static void main(String [] args) {
ReentrantTester rt = new ReentrantTester();
rt.methodA();
}
}
The out put is :
Now I am inside methodA()
Now I am inside methodB()
As in the above code, the ReentrantTester contains two synchronized methods: methodA() & methodB()
The first synchronized method methodA() calls the other synchronized method methodB().
When execution enters the methodA(), the current thread acquires the monitor for the ReentrantTester object.
Now when methodA() calls methodB(), because methodB() is also synchronized, the thread attempts to acquire the
same monitor again. Because Java supports reentrant monitors, this works. The current thread acquire the ReentrantTester's
monitor again and continue the execution of both methodA() and methodB().
The Java runtime allows a thread to reacquire a monitor that it already holds, because Java monitors are
reentrant. These reentrant monitors are important because they eliminate the possibility of a single thread
deadlocking itself on a monitor that it already holds.
This just means once a thread has a lock it may enter the locked section of code as many times as it needs to. So if you have a synchronized section of code such as a method, only the thread which attained the lock can call that method, but can call that method as many times as it wants, including any other code held by the same lock. This is important if you have one method that calls another method, and both are synchronized by the same lock. If this wasn't the case the. The second method call would block. It would also apply to recursive method calls.
public void methodA()
{
// other code
synchronized(this)
{
methodB();
}
}
public void methodB()
{
// other code
syncrhonized(this)
{
// it can still enter this code
}
}
it's about recurse, think about:
private lock = new ReentrantLock();
public void method() {
lock.lock();
method();
}
If the lock is not re-entrant able, the thread could block itself.
I have some confusion regarding thread Synchronization. Consider i have two thread Thread1 and Thread2 and two method synchronized foo1() and foo2(). foo1() is synchronized method and foo2() is not, in foo1 internally there is a statement which calls foo2() and if Thread1 calls foo1() and in that it is working in foo2() method, at the same time Thread2 want to access foo2() method directly which is not synchronized.
So my question is
will Thread2 get access of Foo2()? or it will wait for Thread1 to complete its task?
If foo2() is not synchronized, any thread can call it any time without being blocked. It doesn't make any difference whether a thread is calling it from another method which is itself synchronized.
It is the object, not the method which is locked. This means you can have the two threads in foo1() if they are accessing different objects. If they are accessing the same object, the same lock will prevent concurrent access regardless of what is called first or what calls it.
BTW: foo1() can call itself as it already has the lock.
Thread2 won't be blocked and won't wait.
It will start execution Foo2, since it's not synchronized.
Thread2 can call foo2() directly,because foo2() not a synchronized method,so any thread can call it and not acquire the current object's monitor。
So lets say I have this code:
public void bar(){
synchronized(foo){foo.remove(0)}
}
public void doStuff(){
synchronized(foo){
bar()
}
}
Will synchronized realize that the current chain I'm in has this lock and inherit it or will it deadlock?
The lock you get from a synchronized block is reentrant. This will not dead-lock, a thread can acquire a lock on the same object multiple times.
See Intrinsic Locks and Synchronization.
As Mat said it won't dead lock.
How i see it as
that this lock mechanism isn't dependent over method call but
on control flow.
How a single thread is executing statements and when a thread
encounters a synchronized block then it ask for the lock of the object in the synchronized signature.
If it has it then it enters else will wait in the lock pool of the object until gets notified.
thread which executed doStuff() already carried the lock so thats why no case of deadlock