Can someone explain to me how Reentrant lock and deadlock relate to each other with Java code (pseudo) example?
A reentrant locking mechanism allows the thread holding the lock to re-enter a critical section. This means that you can do something like this:
public synchronized void functionOne() {
// do something
functionTwo();
// do something else
// redundant, but permitted...
synchronized(this) {
// do more stuff
}
}
public synchronized void functionTwo() {
// do even more stuff!
}
In a non-reentrant lock, you would have a deadlock situation when you try to call functionTwo() from functionOne() because the thread would have to wait for the lock...which it holds itself.
Deadlock, of course, is the evil situation in which Thread 1 holds lock A and is waiting for lock B while Thread 2 holds lock B and is waiting for lock A. Thus, neither can continue. This code sample creates a deadlock:
public synchronized void deadlock() throws InterruptedException {
Thread th = new Thread() {
public void run() {
deadlock();
}
}.start();
th.join();
}
The calling thread tries to wait around for the spawned thread, which in turn can't call deadlock() until the caller has exited. Ka-boom!
A deadlock occurs when a thread waits for a condition which will never become true.
The obvious case is when you are trying to lock two locks, locked in a different order by different threads.
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
public void methodA() {
lock1.lock();
lock2.lock();
// do something and unlock both.
}
public void methodB() {
lock2.lock();
lock1.lock();
// do something and unlock both.
}
As you can see it is possible for a thread to call methodA and obtain lock1 waiting for lock2, and another thread to call methodB and obtain lock2 waiting for lock1.
However, it's possible for a thread to deadlock itself. An example is ReentrantReadWriteLock because it doesn't support upgrading a read lock to a write lock.
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
rwl.readLock().lock();
// do we need to update?
rwl.writeLock().lock(); // will wait for the readLock() to be released!
An obscure opportunity to deadlock yourself is when implied locks are used. A static initialiser block is implicitly thread-safe so a lock is used even though static initialiser blocks are not synchronized
class A {
private static int VALUE;
static {
Thread t = new Thread() {
public void run() {
// waits for the A class to load.
VALUE = someLongTask();
}
};
t.start();
// waits for the thread.
t.join();
}
}
Again you have a deadlock!
Here's an example of deadlock with ReentrantLock
class Deadlock {
private static final ReentrantLock l1 = new ReentrantLock();
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("A Trying to lock...");
l1.lock();
System.out.println("A Locked...");
try {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("B Trying to lock...");
l1.lock();
System.out.println("B Must not print");
try {
} finally {
System.out.println("B Trying to unlock...");
l1.unlock();
System.out.println("B Unlocked...");
}
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("A Trying to unlock...");
l1.unlock();
System.out.println("A Unlocked...");
}
}
});
t.start();
}
}
To resolve deadlock, comment out call to t.join, along with enclosing try/catch.
A reentrant lock will allow the lock holder to enter blocks of code even after it has already obtained the lock by entering other blocks of code. A non-reentrant lock would have the lock holder block on itself as it would have to release the lock it obtained from another block of code to reobtain that same lock to enter the nested lock requiring block of code.
As far as deadlock is concerned, if you call a protected block of code from a protected block of code, you'll want a reentrant lock (or you will deadlock while waiting on yourself).
Related
I'm trying to resolve a university exercise. The class AImpl has a method ma(B b) that creates and runs two threads. These threads have to call mb1() and mb2() (they are simple methods that just print a text, so I didn't include them). The calling thread should then wait for mb1() to terminate before finishing.
My logic is:
The first thread enters and after finishing the execution of b.mb1() starts to wait() on the current object, releasing the mutex. Then the second thread runs and it does the same. When they are both waiting, the calling thread calls notifyAll() on the object, waking both of them. They execute b.mb2() and then terminate.
The problem is that when the first thread starts waiting with object.wait(), the control flow doesn't return on the calling thread and the program enters in a deadlock.
Where is my logic flawed?
public class AImpl{
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
BImpl b = new BImpl();
AImpl.ma(b);
}
public static void ma(B b) throws InterruptedException {
Thread thread = new Thread() {
#Override
public void run() {
b.mb1();
synchronized(object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
b.mb2();
System.out.println("Thread finished");
}
};
Thread thread1 = new Thread() {
#Override
public void run() {
b.mb1();
synchronized(object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
b.mb2();
System.out.println("Thread finished");
}
};
thread.run();
thread1.run();
synchronized(object){
object.notifyAll();
}
System.out.println("Program finished.");
}
}
The notify/notifyAll methods tell the scheduler to notify one/all of the threads currently waiting on the lock that notify or notifyAll was called on. But if a thread hasn't started waiting yet then it doesn't get notified.
The solution is to introduce a condition variable that keeps wait from being called if the notifying has happened already. Define it in the same scope as your lock:
public static volatile boolean ready = false;
Then use it to guard the wait block, like this:
while (!ready) {
object.wait();
}
The code calling notify/notifyAll needs to set the variable (it doesn't matter what order you do it in because the notification doesn't happen until the lock is released):
synchronized (object) {
ready = true;
object.notifyAll();
}
What happens:
If the waiting thread gets to the waiting part before the notifying thread does its notifying, then the waiting thread finds ready is false, so it enters the wait method, releases the lock, and stays there. Then the notifying thread changes the flag to true and wakes up the waiting thread, which can leave the wait, reacquire the lock, and then leave the loop now that the flag is set.
But if the notifying thread does its notify before the other thread waits, that's ok, because the ready flag now prevents the thread from entering the wait, it can skip over it.
Further reading: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
I am working on understanding deadlock basics so I came up with below code. I have two threads acquiring locks in opposite order but they're not deadlocking. When I run it I see all the printouts. What am I doing wrong?
public class DeadlockBasics {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public static void main(String[] args) {
DeadlockBasics dk = new DeadlockBasics();
dk.execute();
}
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
// called by thread 1
public void processThis() {
lockA.lock();
// process resource A
System.out.println("resource A -Thread1");
lockB.lock();
// process resource B
System.out.println("resource B -Thread1");
lockA.unlock();
lockB.unlock();
}
// called by thread 2
public void processThat() {
lockB.lock();
// process resource B
System.out.println("resource B -Thread2");
lockA.lock();
// process resource A
System.out.println("resource A -Thread2");
lockA.unlock();
lockB.unlock();
}
}
First of all there is no garantee which threads is start first. To get the deadlock one of the thread has to take a lock on lockA and then the second thread has to take a lock on lockB or visa versa.
public void processThis() {
lockA.lock();
// here the control should be switched to another thread
System.out.println("resource A -Thread1");
lockB.lock();
...
But there may not be enough time to switch between thread because you have just a few lines of code.. It is too fast. To emulate some long work add delay before the second lock to both methods
lockA.lock();
Thread.sleep(200); // 200 milis
Then the second thread will be able to lock lockB before the first release both of them
This could indeed result in a deadlock but not always, for example if the processThis() is completely executed and then the processThat() or vice versa there is no deadlock. You can try to add a Thread.delay(100) or a Thread.yield() to steer the threads execution towards the deadlock or even removing the unlocks to a certain deadlock.
Your code is a good example of dead lock, since ReenttrantLock is a mutual exclusion lock with same behavior as the implicit monitor lock access by using synchronized. However you don't see the deadlock because of this part:
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
After the first thread is created and started, it will takes a while to create the second thread. It takes the JVM about 50 us or maybe even less to create a new thread, it sounds very short, but it is enough for the first thread to be finished and therefore a dead lock will not happen.
I added a Thread.sleep(); into your code so the both threads could be executed somehow parallely.
package com.company;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadlockBasics {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public static void main(String[] args) {
DeadlockBasics dk = new DeadlockBasics();
dk.execute();
}
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
// called by thread 1
private void processThis() {
lockA.lock();
// process resource A
try {
Thread.sleep(1000); //Wait for thread 2 to be executed
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1 will own lock a");
lockB.lock();
// process resource B
System.out.println("Thread 1 will own lock b");
lockA.unlock();
lockB.unlock();
// Both locks will now released from thread 1
}
// called by thread 2
private void processThat() {
lockB.lock();
// process resource B
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2 will own lock b");
lockA.lock();
// process resource A
System.out.println("Thread 2 will own lock a");
lockA.unlock();
lockB.unlock();
// Both locks are released by thread 2
}
}
Two points:
Release locks in the reverse order of acquiring them. That is, processThis should reverse the order of removing the locks. For your example, the order doesn't matter. But if processThis attempted to acquire a new lock on A before releasing the lock on B a deadlock could again occur. More generally, you'll find it easier to think about locks by considering their scope and by avoiding overlapping but non-enclosing scopes.
To better highlight the problem, I would put in call to wait after acquiring the first lock in each of threads, and have execute launch both threads then invoke notify on both threads.
I'm trying to have a Thread2 wait for a String and Thread1 to notify on String update, I do synchronize The String object as code below shows, But I still get IllegalMonitorStateException Here's my code
public class Class1{
String string = "";
public Class1(){
Thread t1 = new Thread(){
public void run(){
synchronized(string){
string = "Something"; string.notifyAll(); //This is the line that throws an IllegalMonitorStateException
}
}
};
Thread t2 = new Thread(){
public void run(){
synchronized(string){
try{
string.wait();
}catch(Exception e){
e.printStackTrace();
}
}
}
};
t2.start();
t1.start();
}
}
There's nothing in StackTrace except highlighting string.notifyAll()
Your code contains a data race because it accesses the mutable string variable outside of a synchronized block. Specifically, this happens on the line synchronized(string). While dereferencing string to reach the object whose monitor will be locked, the thread does not already hold a lock on that object. Therefore you have no guarantee which object it will acquire a lock on.
The fact that you mutate the string variable means that it now points to some other object. When the next thread acquires a lock on that new object, it will not benefit from any happens-before relationship because it is the first thread to ever acquire a lock on it. Mutual exclusion will not be guaranteed, either, because there may be arbitrarily many threads, each locking a different String instance without contention.
Combining the two phenomena described above we can also see that there is no guarantee that the object reached on the line synchronized(string) will be the same one as the one reached from within the synchronized block. Once it happens that this is indeed a different object, your IllegalMonitorStateException ensues.
In summary, the situation is very similar to the synchronized block not existing at all.
All of the above problems can be avoided if you keep to the best practice of using dedicated final variables to refer to objects used for locking. In a nutshell, and fixing the compilation errors in your example, this is what you would have to write:
static String string = "";
static final Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
synchronized (lock) {
... update the string variable ...
lock.notifyAll();
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
t2.start();
t1.start();
}
I am trying to understand how deadlocks are created. I've understood that by using two threads on two synchronized methods, a deadlock can be created.
Went through many examples from the net.
Can a deadlock be created with wait and notify?
Every time a thread is on wait, it will be notified. So how does this end up in a deadlock?
Illustration of an example will be helpful.
Deadlock is caused when two threads try to obtain the same, multiple locks in different order:
// T1
synchronized (A) {
synchronized (B) {
// ...
}
}
// T2
synchronized (B) {
synchronized (A) {
// ...
}
}
The only way to prevent deadlocks is to make sure that all threads obtain locks in the same order--either they all do A then B, or they all do B then A.
If you don't have multiple locks, then you don't have a deadlock. However, you can get thread starvation or other things that may look similar to deadlock.
Say thread 1 enters a synchronized block on method A and then waits. Thread 2 then attempts to enter the synchronized block on method A. Thread 1 is waiting for a notify, and thread 2 is waiting on the synchronized block. Everything is now waiting. Some other thread will have to notify the object on which thread 1 is waiting. This is just one scenario that can create a deadlock. There are all kinds of ways to do it.
A thread which is on wait will not be notified unless some code explicitly notifies it. Therefore the example you are looking for is absolutely trivial:
public static void main(String[] args) {
synchronized(String.class) {
String.class.wait();
}
}
and this hangs forever. Technically, though, it is not a deadlock, which requires two or more threads involved in a closed cycle where each thread waits for the next one to unblock it.
Something close to wait/notify deadlock:
public class Example
{
volatile boolean isNotified = false;
public synchronized void method1() {
try
{
isNotified = false;
while (!isNotified)
wait();
notifyAll();
System.out.println("Method 1");
} catch (InterruptedException e) {/*NOP*/}
}
public synchronized void method2() {
try {
isNotified = true;
while (isNotified)
wait();
notifyAll();
System.out.println("Method 2");
} catch (InterruptedException e) {/*NOP*/}
}
public static void main(String[] args)
{
Example example = new Example();
Thread thread1 = new Thread()
{
public void run()
{
example.method1();
}
};
Thread thread2 = new Thread()
{
public void run()
{
example.method2();
}
};
thread1.start();
thread2.start();
}
}
I am getting an Illegal State exception for following code :
synchronized (this) {
try {
Thread.currentThread().wait();
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
What i could made is synchronized on "this" will capture Monitor on Object calling the method and since i am calling wait on Current Thread object and i really don't have lock on that i am getting t error. Please validate my theory.
You call wait on the current thread, call it on this.
this.wait();
but then you will never get a notifyAll , because no thread that enters the synchronized block
can ever reach the notofyAll method. They all will wait for it first.
I guess you want one Thread to wait for another Thread to do some work.
Here is a short example of how synchronization between threads can work
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Object monitor = new Object();
Thread t1 = new Thread(new R1(monitor));
Thread t2 = new Thread(new R2(monitor));
t1.start();
t2.start();
t2.join();
t1.join();
}
public static class R1 implements Runnable {
private Object monitor;
public R1(Object monitor) {
this.monitor = monitor;
}
public void run() {
System.out.println("R1 entered run");
synchronized (monitor) {
try {
monitor.wait();
System.out.println("R1 got monitor back");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static class R2 implements Runnable {
private Object monitor;
public R2(Object monitor) {
this.monitor = monitor;
}
public void run() {
System.out.println("R2 entered run");
synchronized (monitor) {
System.out.println("R2 will sleep for 1 sec");
try {
Thread.sleep(1000);
System.out
.println("R2 will notify all threads waiting for monitor");
monitor.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Output is:
R1 entered run
R2 entered run
R2 will sleep for 1 sec
R2 will notify all threads waiting for monitor
R1 got monitor back
You have acquired the lock of
this(current object)
and you are calling `
wait()
` on current thread that is why.
you should acquire lock before calling wait, notify notifyAll
Case1
...
synchronized(this){
this.wait();
}
...
Case2
...
synchronized(this){
Thread.currentThread.wait();
}
...
Case 1 is sensible code. It waits until another thread calls notify[All]() on "this" object.
Case 2 looks silly. It could only execute if the current thread and "this" were the same object, or you already had a lock on the current thread. Otherwise, you'd get IllegalMonitorStateException. Synchronising on Thread objects is a Bad Thing, because you can't be sure what else might be synchronising on them.
By the way, if what you want to do is just pause for a while in the program, you should sleep(), not wait().
From the Java doc for Object class wait() method:
IllegalMonitorStateException - if the current thread is not the owner
of the object's monitor.
In your code, current thread is the owner of the monitor of this and wait is called on Thread.currentThread.
Replace Thread.currentThread().wait(); with this.wait();