Calling a synchronized block from another synchronized block with same lock - java

I have this class:
public class MyClass {
public MyClass(){}
public void actionA(){
synchronized(MyClass.class){
System.out.print("A");
}
}
public void actionB(){
synchronized(MyClass.class){
actionA();
}
}
}
Which one (if any) is true?
Calling actionB() will lead to a deadlock, since actionA() can never aquire the lock associated with MyClass.class
Calling actionB() will not lead to a deadlock, since it already has aquired the lock associated with MyClass.class

#2 will happen, since the calling thread has the lock.
If however the code looked like this:
public void actionB(){
synchronized(MyClass.class) {
Thread thread = new Thread(new Runnable { run() { actionA(); }});
thread.start();
thread.join();
}
}
Then you would have a deadlock. locks are acquired on a per thread basis.
I find a useful mental picture is of a shared key for a padlock. Only one thread can have the key at a time, but obviously the same key will open any lock which it fits (the key fits any lock that uses the same sync object).
As an aside, it is bad practice to synchronize on any publicly visible field, since another piece of code far removed could feasibly lock on the same object leading to unnecessary contention and possibly deadlocks.

#2 will be happen.
Reentrant Synchronization
Recall that a thread cannot acquire a lock owned by another thread.
But a thread can acquire a lock that it already owns. Allowing a
thread to acquire the same lock more than once enables reentrant
synchronization. This describes a situation where synchronized code,
directly or indirectly, invokes a method that also contains
synchronized code, and both sets of code use the same lock. Without
reentrant synchronization, synchronized code would have to take many
additional precautions to avoid having a thread cause itself to block.

Related

How the lock remains on the object held by a thread after it gets destroyed?

I know that the destroy() method in java is deprecated, just wanted to know if the thread holds a lock on the particular object and after we call a destroy method for thread, it gets terminated so how the lock on that object doesn't get released?
When thread is dead, how the object is still remains locked?
The javadoc for the Thread::destroy (in Java 7) says this:
Deprecated. This method was originally designed to destroy this thread without any cleanup. Any monitors it held would have remained locked. However, the method was never implemented. If it were to be implemented, it would be deadlock-prone in much the manner of suspend(). If the target thread held a lock protecting a critical system resource when it was destroyed, no thread could ever access this resource again. If another thread ever attempted to lock this resource, deadlock would result. Such deadlocks typically manifest themselves as "frozen" processes.
So, your question is moot.
The method was not implemented. It is not possible to say definitively what behavior would have been. Only what they originally intended it would be.
Having said that, the stated intention was that there would be no cleanup on destroy(), meaning:
primitive locks acquired using synchronized would not have been released,
finally blocks would not have been executed, and
"resources" managed using try with resource would not have been closed.
The javadoc says that if you do call destroy() on a Thread the the behavior is to throw NoSuchMethodError. Normal exception behavior will ensue. Primitive locks will be released, and so on.
But ... just ... don't.
Finally, if you are talking about Lock objects instead of primitive locks, these are only ever released if your code explicitly calls Lock::unlock. The javadoc for Lock recommends that you lock and lock using try ... finally like this:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
... "in most cases". If you consistently use this idiom, then you can be sure that any locks will always be released when a thread terminates. (But that wouldn't have worked if destroy() had been implemented as envisaged.)
In this example you can see lock is not released upon thread termination:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
public class CheckThreadLock {
public static void main(String[] args) {
final Lock reentrantLock = new ReentrantLock();
Thread myThread = new Thread() {
#Override
public void run() {
System.out.println(Thread.currentThread()+": myThread acquire lock");
reentrantLock.lock();
System.out.println(Thread.currentThread()+": Lock aquired: wait...");
LockSupport.parkNanos(1_000_000_000);
System.out.println(Thread.currentThread()+": Quiting thread");
}
};
myThread.start();
LockSupport.parkNanos(500_000_000);
System.out.println(Thread.currentThread()+": Acquire lock");
reentrantLock.lock();
System.out.println(Thread.currentThread()+"; Success!");
}
}
Output:
Thread[Thread-0,5,main]: myThread acquire lock
Thread[Thread-0,5,main]: Lock aquired: wait...
Thread[main,5,main]: Acquire lock
Thread[Thread-0,5,main]: Quiting thread
//Success never happens because of deadlock

Java wait without lock release

How can I make a thread wait without releasing the lock ?
If this is not possible, then how can I pause a thread while a certain condition is not met and unpause it as soon the condition is met or when I notify it
Concept of wait/notify
Waiting/Notifying can only be done in the scope of a lock (e.g. a synchronized method or synchronized block).
Both the wait and notify should synchronize on the same object.
The waiting thread:
synchronized(lockObject) {
lockObject.wait(); <-- it will wait here until the notify is called.
}
The notifying thread:
synchronized(lockObject) {
lockObject.notify();
}
The lockObject can be anything. It could just be a new Object(), but very often it could be some collection, a logical object that represents a printer, ... anything.
Hint: Judging from the comments section, you may need the following: The notify releases just one waiting thread. But you could actually have multiple threads waiting. If you want to release all of them, use notifyAll.
Same thing, but with synchronized methods
Alternatively, you could create a class, and use method level locking.
class LockObject {
public synchronized void waitMethod() {
wait();
}
public synchronized void notifyMethod() {
notify();
}
}
Again both have to use the same object to lock on.
LockObject instance = new LockObject();
Then the waiting thread:
instance.waitMethod();
And the notifying thread:
instance.notifyMethod();
If you are serious about this
Also take a look inside the concurrency packages and tutorials of the JDK, and you will find more advanced locking objects. Just to name one, countdown latches are powerful.

Understanding lock scope

From this link, I understand "Since the lock() and unlock() method calls are explicit, we can move them anywhere, establishing any lock scope, from a single line of code to a scope that spans multiple methods"
So what I understand from the above statement is
public class Test {
Lock l = new ReentrantLock();
void myMethod1() {
l.lock();
// Do my stuff here
}
void myMethod2() {
// Do more stuff here
l.unlock();
}
}
So basically 1 can call method1 and method2 in sequence and assume the call is thread safe.
I am not sure if it's true as said above.
What if somebody just calls method2 when i am already executing method1/method2 pair? Doesn't it complicate things.
I think a lock should be acquired and released in the function itself, before the control is returned from the function. Is my understanding correct?
Answer to first question:
What if somebody just calls method2 when i am already executing
method1/method2 pair? Doesn't it complicate things.
Suppose another thread calls the unlock() method on the ReentrantLock object then IllegalMonitorStateException would be thrown. Because the thread is not acquiring the lock and when it tries to unlock then it get exception.
It will not have any effect on execution or locking of first thread which is acquiring the lock.
Same thread:
Lock: If same thread which is acquiring the lock again tries to acquire the lock then lock counter increments.
Unlock: If same thread which is acquiring the lock tries to unlock then lock counter decrements and as soon as lock counter becomes 0, thread releases the lock.
Different thread:
Lock: 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.
Unlock: If different thread tries to unlock when it is NOT holding the lock then IllegalMonitorStateException is thrown.
That is the reason ReentrantLock lock and unlock mandates you to have try-catch or throw mechanism because it throws exception.
Read below excerpt from ReentrantLock#unlock()
If the current thread is the holder of this lock then the hold
count is decremented. If the hold count is now zero then the lock is
released. If the current thread is not the holder of this lock then
{#link IllegalMonitorStateException} is thrown.
Answer to second question:
I think a lock should be acquired and released in the function itself,
before the control is returned from the function. Is my understanding
correct?
That's the whole purpose of ReentrantLock, you can extend the locking mechanism to other methods, which you cannot do with synchronized blocks and methods. See below from ReentrantLock
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.
What if somebody just calls method2 when i am already executing method1/method2 pair? Doesn't it complicate things.
java.util.concurrent.locks.Lock is a more powerful mechanism than synchronized. Power tools are dangerous. Use them with caution.
See #hagrawal's answer for details.
Consider this example instead:
public class Test {
...
public void method1() {
l.lock();
...
}
public void method2() {
l.lock();
...
while (l.isHeldByCurrentThread()) {
l.unlock();
}
}
}
This setup means that once Thread A calls method1(), Thread B will block when calling any of the methods until Thread A calls method2(). So the lock scope spans zero or more invocations of method1() followed by a single invocation of method2().
Though in practice I would consider it far easier and cleaner to write code that restricts lock scope to a single method or part of a method.

Calling a synchronized method from of a synchronized method, both of the same object [duplicate]

This question already has answers here:
Is it safe to call a synchronized method from another synchronized method?
(3 answers)
Closed 9 years ago.
Why doesn't the code below lead to a deadlock? I mean after i call getNumber(.) the object of the class Test should be locked, so I shouldn't be able to access getNumber2(.).
class Test() {
synchronized int getNumber(int i){
return getNumber2(i);
}
synchronized int getNumber2(int i) {
return i;
}
public static void main(String[] args) {
System.out.println((new Test()).getNumber(100));
}
}
Output:
100
This is because the lock is re-entrant, meaning that it can be acquired multiple times by the same thread.
From the Java tutorial:
Reentrant Synchronization
Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.
The relevant part of the JLS is ยง17.1. Synchronization:
The Java programming language provides multiple mechanisms for communicating between threads. The most basic of these methods is synchronization, which is implemented using monitors. Each object in Java is associated with a monitor, which a thread can lock or unlock. Only one thread at a time may hold a lock on a monitor. Any other threads attempting to lock that monitor are blocked until they can obtain a lock on that monitor. A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.
It doesn't lead to a deadlock because when a thread enter a synchronized method, what it does is checking that it has a lock on this, then if it doesn't, it waits until it can have the lock and get it.
When the thread enters the second synchonized method in your case, it already has the lock on the this object, so it can enter the method without blocking.

Java lock and happend-before relation

I'm not sure if I'm interpreting the javadoc right. When using a ReentrantLock after calling the lock method and successfully gaining a lock, can you just access any object without any synchronized blocks and the happend-before relationship is magically enforced?
I don't see any connection between the ReentrantLock and the objects I'm working on, that's why it is hard to believe I can work on them safely. But this is the case, or am I reading the javadoc wrong?
If thread A has modified some object inside a code block CB1 guarded by the lock and then releases the lock, and thread B enters in a code block guarded by the same lock, then thread B will see the modifications done by thread A in the code block CB1.
If two threads read and write the same shared state, then every read and write to this state should be guarded by the same lock.
It's ... a (mutex) lock:
void myMethod()
{
myLock.lock(); // block until condition holds
try
{
// Do stuff that only one thread at a time should do
}
finally
{
myLock.unlock()
}
}
Only one thread can hold the lock at a time, so anything between the lock() and unlock() calls is guaranteed to only be executed by one thread at a time.
The relevant Oracle tutorial can be found here.
There's no magic in it. You're safe if, and only if, all threads accessing an object use the same lock - be it a ReentrantLock or any other mutex, such as a synchronized block.
The existence ReentrantLock is justified by that it provides more flexibility than synchronized: you can, for example, just try to acquire the lock - not possible with synchronized.

Categories

Resources