Recursive Synchronization vs Recursive Reentrant Lock - java

I know thread is allowed to acquire a monitor owned by itself i.e. In Java, synchronized locks are reentrant as shown in example below.
My query is if i use java.util.concurrent.locks.ReentrantLock API it will produce the same result or not, Can we have dead lock in synchronized but never in java.util.concurrent.locks.ReentrantLock
e.g.
final Object[] objects = new Object[10]
public synchronized Object setAndReturnPrevious(int index, Object val) {
lock.lock();//If i use this will it be same as above synchronization
set(index, val);
lock.unlock()//;
}
public synchronized void set(int index, Object val) {
lock.lock();//
objects[index] = val;
lock.unlock();//
}

If you look at the Java doc (here) and the point is very clear (emphasis mine):
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.
The main point is that they both behave with the same concept, but ReentrantLock lock provides additional methods to lock()/unlock()/etc.. methods which you can use them explicitly in different code blocks (methods).

Both synchronized and reentrant locks are same . if you want more control and want to solve complex synchronization problems than Reentrant Lock is the best choice. it adds additional functionality to the implicit synchronization like ** support for Condition variables , Lock Fairness etc.**
As a Reference Check Java Threads 3rd Ed - Chapter 3 and Onwards

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.

Mutex in Java 1.4 [duplicate]

This question already has answers here:
Java 1.4 synchronization: only allow one instance of method to run (non blocking)?
(4 answers)
Closed 6 years ago.
I need to isolate function myFunc() from executing from several threads. I know how to solve this task with Mutex. Since Java 1.4 not supports Mutex how to solve this task in another way?
In Java all objects have an intrinsic lock, also called a monitor lock. This is enough to provide simple mutual exclusion but it does have limitations.
public final class MyClass1 {
public synchronized void myFunc() {
// Exclusive work here
}
}
The synchronized keyword on the method means that the intrinsic lock of the MyClass1 object instance must be acquired before myFunc can run.
public static final class MyClass2 {
private final Object mutex = new Object();
public void myFunc() {
synchronized (mutex) {
// Exclusive work here
}
// There is no mutual exclusion here
}
}
A block inside of a method can be synchronized for the scope of the block. This also allows you chose the object to acquire the lock of.
An intrinsic lock will either be acquired eventually or the thread will hang. An attempt to acquire an intrinsic lock does not timeout and cannot be interrupted.
An intrinsic lock is reentrant so you do not need to worry about a thread deadlocking with itself. Deadlocks can still happen when acquiring locks in different orders.
The synchronized keyword also ensure memory visibility of reads and write when they both take place in a synchronised code that locks the same object.
https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
https://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html
You should also know that the Java memory model has changed since 1.4 so much of the current information will not be applicable.
https://www.ibm.com/developerworks/library/j-jtp03304/

Non-synchronised methods of an object in Java?

I need to clear a few basic concepts so as to check whether my understanding is correct or not.
1) Once a thread enters any synchronized method on an instance, no other thread can enter any other synchronized method on the same instance.
2) However, nonsynchronized methods on that instance will continue to be callable (by other threads). If yes, can I then say the whole object doesn't gets locked but only the critical methods which are synchronized.
3) Will I get the same behaviour as above for synchronized statement too:
synchronised(this){
// statements to be synchronised
}
or the whole object gets locked here with nonsynchronized methods on that instance not callable.
I think I am pretty confused with locking scope.
A lock only prevents other threads from acquiring that same lock -- the lock itself has no idea what it protects -- it's just something that only one thread can have. We say the whole object is locked because any other thread that attempts to lock the whole object will be unable to acquire that lock until it's released. Otherwise, your understanding is correct.
Your statements are correct. Only synchronized code becomes protected. The object is simply used as the synchronizing lock, and it is not itself "locked".
And yes, you get the same behavior for synchronized blocks on the same object. In fact, you can synchronize blocks in the code of one object using another object as the lock.
The code,
public synchronized void abc() {
...
}
it is conceptually same as,
public void abc() {
synchronized(this) {
}
}
In either of these cases the non-synchronized methods can be called when the monitor (in this case the object on which the method abc is called) is locked by a Thread executing a synchronized block or method.
Your understanding is correct. All three statements you made, are valid.
Please note one thing though, locks are not on methods(synchronized or non-synchronized). Lock is always on the object, and once one thread acquired the lock on an object, other threads have to wait till the lock is released and available for other threads to acquire.

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.

Categories

Resources