This snippet shows an example of a deadlock in Java by forcing Thread1 to acquire lock1 on resource1 and Thread2 to acquire lock2 on resource2. Then Thread1 tries to acquire lock2 and Thread2 tries to acquire lock1.This causes a deadlock.
I was expecting to see Thread2 and Thread1 state to be BLOCKED according to this, instead, they are in WAITING state indefinitely when I monitor the status with thread.getState().
Can you help me understand why?
Consider that the locks are declared in the main class as:
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();
This is the code of the ThreadClass
import java.util.concurrent.locks.Lock;
public class ThreadClass extends Thread {
private Lock lock1;
private Lock lock2;
private Resource resource1;
private Resource resource2;
public ThreadClass(Resource resource1, Resource resource2, String name, Lock lock1, Lock lock2) {
this.resource1 = resource1;
this.resource2 = resource2;
this.lock1 = lock1;
this.lock2 = lock2;
this.setName(name);
}
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread1")) {
lock1.lock();
System.out.println(Thread.currentThread().getName() + ": Using " + resource1.name);
// Simulating work on RESOURCE 1
lock2.lock();
System.out.println(Thread.currentThread().getName() + ": Using " + resource2.name);
// Simulating work on RESOURCE 2
lock2.unlock();
lock1.unlock();
}
if (Thread.currentThread().getName().equals("Thread2")) {
lock2.lock();
// Simulating work on RESOURCE 2
lock1.lock();
System.out.println(Thread.currentThread().getName() + ": Using resource1");
lock1.unlock();
lock2.unlock();
}
}
}
The documentation you refer to is about the intrinsic locks - the ones built into every Java object (also called monitors). They are a low level, slightly legacy mechanism with known caveats. The intrinsic locks are used with the
synchronizedkeyword and are only taken when a thread enters a block of code statically marked assynchronized.You are using a different, higher level API, so whatever the documentation says about locks - does not apply. I have never looked inside the implementation of the
ReentrantLock, but - as you can see from theThreads status - it's not using thesynchronizedblock to park the thread, but rather a call to theObject'swaitmethod (which is always made from inside asynchronizedblock and forms the other low-level primitive upon which Java's threading is built).