Is using ReentrantLock reliable as synchronized? - java

I searched a lot but was confused with the process of 'ReentrantLock' and normal 'synchronized' .
For example(1):
Object obj = new Object();
synchronized(obj){
//lock is guaranteed to be acquired
}
example(2)
Lock lock = new ReentrantLock();
lock.lock(); //problem here
try{
//dostuff
}
finally{
lock.unlock();
}
My question is:
In example 1: it is guaranteed to acquire a lock on the object using the synchronized keyword.
But
In example 2: is it guaranteed that the lock will be acquired using the lock.lock() method?? or will the thread proceed to the next line for the execution?? without acquiring the lock.
I doubt it because, using threads had resulted in unexpected outcomes for me many times.

Only one thread will acquire the lock: this is the contract of ReentrantLock.
Therefore your example 2 is perfectly thread safe.

Related

What exactly is "re-entrant" in a Reentrant lock in Java? [duplicate]

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.

how the synchronized keyword lock the method or block using the object

When we want to lock the block by synchronized statements we pass a object to it , I want to know that how this object lock the block , actually I want to know the mechanism of lock by synchronized keyword.
example :
Object object = new Object();
synchronized (object) {
//do something
}
my question is how object lock the block .
When a thread encounters a synchronized block (which uses objects for synchronization, as in your example) the following happens:
the Java runtime checks if an other thread has already started executing the synchronized block (and is not finished yet) with the same "blocking" object instance
If yes: our thread must wait (it is blocked) until the other thread finishes. After the other thread releases the lock (and no other waiting thread acquires the lock before out thread), ours can enter the block
If no: our thread can immediately enter the synchronized block
The same instance is a very important part, consider the following example:
public void method() {
Object object = new Object();
synchronized (object) {
//do something
}
}
In this example synchronization will effectively never happen, threads will never block. Because each thread creates a new instance before encountering the block. They never use the same.

Why does 'wait() method within synchronized block' have deadlock possibility?

klocwork JD.LOCK.WAIT issue is reported when an Object.wait() method is called while the method is holding two or more locks.
klocwork says that waiting on a monitor while two locks are held may cause deadlock and the issue should be taken into account.
But I cannot understand why this causes deadlock.
Who can help me understand this issue?
Following code is from klockwork. The JD.LOCK.WAIT issue occurs on line 14 lock.wait();.
String name;
synchronized void waitForCondition(Object lock) {
try {
synchronized(lock) {
name = "aa";
lock.wait(); //line 14
}
} catch (InterruptedException e) {
return;
}
}
Lets say t1 enters the waitForCondition() method. So t1 now has this as a lock. Meanwhile, some other thread has just acquired lock object and is trying call waitForContion().
t2 holds lock but is waiting for this to enter waitForContion().
t1 holds this but is waiting for lock to exit waitForContion().
That is a deadlock. Neither of them can make any progress and are waiting on each other.
To avoid this, one strategy is to make sure any thread has all the resources it needs to complete. Here it means that lock and this can only be acquired together and not otherwise.
Also, when lock.wait() is called, only lock is released while this is not. So, in such a case no thread can call waitForContion() on that object.

What is the meaning of "ReentrantLock" in Java?

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.

Does a synchronized objects handle pass to a called function in Java?

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

Categories

Resources