What is the meaning of "ReentrantLock" in Java? - 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.

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.

Java Lock explanation

I can't understand the following code:
public class Counter {
private long value;
private Lock lock;
public long getAndIncrement() {
lock.lock();
try {
int temp = value;
value = value + 1;
} finally {
lock.unlock();
}
return temp;
}
}
What I can't understand is how Lock is instantiated while it's an interface?
And if it's an anonymous class that implements Lock interface, why I can't see any override of Lock functions (e.g. lock() and unlock() ) ?
In short, the following line really confuses me.
private Lock lock;
What is lock here? What is its type?
Edit:
Lock is an interface and can't be instantiated. After looking at the constructor:
public Counter(){
lock = new ReentrantLock();
}
Now, everything is clear. (Thanks to Bhushan Uniyal )
Q how Lock is instantiated while it's an interface?
Lock in an interface, implemented by ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
From Java Doc
A reentrant mutual exclusion Lock with the same basic behavior and
semantics as the implicit monitor lock accessed using synchronized
methods and statements, but with extended capabilities.
A ReentrantLock is owned by the thread last successfully locking, but
not yet unlocking it. A thread invoking lock will return, successfully
acquiring the lock, when the lock is not owned by another thread. The
method will return immediately if the current thread already owns the
lock. This can be checked using methods isHeldByCurrentThread(), and
getHoldCount().
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. Programs using fair locks accessed by many
threads may display lower overall throughput (i.e., are slower; often
much slower) than those using the default setting, but have smaller
variances in times to obtain locks and guarantee lack of starvation.
Note however, that fairness of locks does not guarantee fairness of
thread scheduling. Thus, one of many threads using a fair lock may
obtain it multiple times in succession while other active threads are
not progressing and not currently holding the lock. Also note that the
untimed tryLock method does not honor the fairness setting. It will
succeed if the lock is available even if other threads are waiting.
lock()
Acquires the lock.
Acquires the lock if it is not held by another thread and returns
immediately, setting the lock hold count to one.
If the current thread already holds the lock then the hold count is
incremented by one and the method returns immediately.
If the lock is held by another thread then the current thread becomes
disabled for thread scheduling purposes and lies dormant until the
lock has been acquired, at which time the lock hold count is set to
one.
Lock is a interface and you need to provide it implementation of Lock, there are already some classes which provide the implementation of Lock , ReentrantReadWriteLock.ReadLock, ReentrantLockReentrant, ReadWriteLock.WriteLock,
e.g;
Lock lock = new , ReentrantLockReentrant();
also you can provide your own implementation
public class MyLock implements Lock {
public void lock() {
}
public void lockInterruptibly() throws InterruptedException {
}
public boolean tryLock() {
return false;
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
public void unlock() {
}
public Condition newCondition() {
return null;
}
}
A lock is a thread synchronization mechanism like synchronized blocks except
locks can be more sophisticated than Java's synchronized blocks. Locks (and other more advanced synchronization mechanisms) are created using synchronized blocks, so it is not like we can get totally rid of the synchronized keyword.
From Java 5 the package java.util.concurrent.locks contains several lock implementations, so you may not have to implement your own locks. But you will still need to know how to use them, and it can still be useful to know the theory behind their implementation.

Does synchronized (this) lock only the synchronized block or all the "this" code?

public class ObjectCounter {
private static long numOfInstances = 0;
public ObjectCounter(){
synchronized(this){
numOfInstances++;
}
}
**public static synchronized long getCount(){
return numOfInstances;
}**
//vs//
**public static long getCount(){
return numOfInstances;
}**
}
if I'll run few threads, some of them call the static function getCount() and some of them create new instances. I want to get in each call to getCount() the real number of instances at the time.
Is there a difference between the two options in the code?
If I lock "this" shouldn't it mean that I can't call getCount() until the constructor exits the synchronized block (lets say if I don't write synchronize on the getCount()).
if I do a synchronized block in some place in the code, does it lock only the synchronized block or all the "this" code?
From here down EDIT: thank you all, it was very helpful, but I have a few more questions following your answers.
If I understand correctly, the synchronized(this) block doesn't effect (or connected to) the static synchronized function (in lock terms not the numOfInstances increment)?
is there a better option to make the increment and the getCount() function Thread-safe? (like open a static object and do synchronized(obj) instead synchronized(this) - friend suggested).
If I had a f1() method (non-static) in ObjectCounter class, while one thread is in the synchronized(this) can other thread enter f1() block (not a synchronized class or have synchronized block inside)?
If I had a f1() method (non-static) and f2() method (non-static) in ObjectCounter, in f1() I have synchronized(this) block. while one thread is in the synchronized(this) block, can other thread enter f1() block (not a synchronized class or have synchronized block inside)? (lets say both of the threads "working" on the same instance)
`
Using synchronized means in order for a thread to execute that block or method, it has to acquire a lock referenced (explicitly or implicitly) by that block or method. For the static synchronized methods, that lock is the monitor on the class object. For the synchronized(this) block, the lock used is the monitor on the current instance. Sharing of locks between multiple methods or blocks is what enforces atomicity and memory visibility of updates, also the shared lock provides a shared communication path through which waiting and notification can take place.
Since the static synchronized blocks use a different lock from that used by the block in the constructor, entering a static synchronized block is not blocked by another thread's accessing the block that requires acquiring the lock on the current instance, and the synchronized block in the constructor has no effect on anything, the lock acquisition will always be uncontended. More importantly here, changes made by one thread in the constructor may not get seen by other threads using the getter. Synchronization affects both locking and memory visibility.
This changed version would work:
public class ObjectCounter {
private static long numOfInstances = 0;
public ObjectCounter(){
synchronized(ObjectCounter.class){
numOfInstances++;
}
}
public static synchronized long getCount(){
return numOfInstances;
}
}
because the getter and the incrementing block are using the same lock. Making the different threads acquire the same monitor ensures that the change to the counter gets safely published so that another thread accessing the getter can see the updated value.
The synchronized keyword says, "you have to acquire a lock before you can enter", where for the method the lock is assumed: with the static keyword on the method it's the monitor on the class, without a static keyword it's the monitor on the current instance. For locking to work correctly the different blocks and methods need to use the same lock. There is arguably too much syntax sugar and too much making things convenient in how Java was designed: allowing implicit choice of locks and putting the monitor on java.lang.Object can cause confusion.
WRT your question #6: For what you're doing here you'd be better off with an AtomicLong. Use synchronized blocks for coordinating multiple changes that need to take place without interference from other threads.
Questions #3, #7 and #8 seem very similar: If a method/block isn't attempting to acquire a lock, nothing prevents threads from executing that method/block. The object as a whole doesn't get any protection, using the synchronized methods or blocks to enforce locking is what does the protecting. Think less in terms of "using the synchronized keyword" and more in terms of what lock threads need to acquire.
Yes there is a difference in the options. In the above option, two threads cannot call getCount() at the same time, in the below one they can.
Yes, that is correct. There can only be one thread at the same time holding a lock on an object.
Each object has its own lock. So it lock all synchronized (this) block of that object.
Note, however, that each object has a lock of its own and also each class has a lock of its own. In the constructor you use the object lock to access a static (class) variable, while in getCount() you use the class lock. That means that your code is not thread-safe!
synchronized steps:
Check if object lock is already acquired. If so, proceed into synchronized block/method
Attempt to aquire lock. If the lock has already been acquired by another thread, then the thread will wait for the lock to be released, at which point it will go through the cycle (2.) again
Is there a difference between the two options in the code?
Yes, there is clear difference. In first, you are synchronizing threads access to getCount() method on the class object of ObjectCounter. While in second you are not.
If I lock "this" shouldn't it means that I can't call getCount() until
the contractor exit the synchronized block (lets say if I don't write
synchronize on the getCount()).
Since there is only one lock of an object (class locks are different which are held through using static keyword along with synchronized), so if some other thread is acquiring that lock either because of synchronized(this){ or because of this synchronized long getCount(){ then the new thread trying to acquire the lock has to wait until the previous thread has released the lock.
Now since in your case, you are doing, static synchronized long getCount(){, so, its locking becomes different from synchronized(this){. Which means that if some thread is acquiring a lock because of synchronized(this){ and some other thread is trying to invoke getCount() then that thread will not be blocked.
if I do a synchronized block in some place in the code, does it locks
the only the synchronized block or all the "this" code?
Non-static synchronization:
If you do synchronized block in some place in the code and it is non-static public synchronized long getCount(){, then also the lock of your object will be held, so new thread trying to acquire the lock has to wait until the previous thread has released the lock.
Static synchronization:
If you do synchronized block in some place in the code and it is static public static synchronized long getCount(){, then it will have no effect on lock of non-static sychronization.
Bottom line:
There is only and only one lock for one object, and if that lock is acquired by some thread then other threads has to wait until that lock released.
Then there is a class lock, which is held if static keyword is used along with synchronized keyword.

Does deadlock happen per method or per class?

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

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