I'm having a hard time understanding the behavior of ReentrantLock.lock()
I have the following class
import java.util.concurrent.locks.*;
class BlockingClass {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void a() {
lock.lock();
System.out.println("called in method a(): lock()");
try {
System.out.println("called in method a(): await()");
condition.await();
}
catch (InterruptedException e) {}
finally {
lock.unlock();
System.out.println("called in method a(): unlock() ");
}
}
public void b() {
lock.lock();
System.out.println("called in method b(): lock()");
System.out.println("called in method b(): signalAll()");
condition.signalAll();
lock.unlock();
System.out.println("called in method b(): unlock() ");
}
}
which I run with the following test:
class BlockingClassTest {
public static void main(String[] args) throws InterruptedException {
final BlockingClass blockingClass = new BlockingClass();
new Thread() {
public void run() {
System.out.println("Thread1 calling a()");
blockingClass.a();
}
}.start();
Thread.sleep(1000);
new Thread() {
public void run() {
System.out.println("Thread2 calling b()");
blockingClass.b();
}
}.start();
}
}
I would have expected a deadlock. Once the a() method calls lock.lock(), I would expect that anyone calling the b() method would have to wait at b's lock.lock() until the thread calling a() had called lock.unlock(). But since a() is waiting for b() to call condition.signalAll(), both methods should have stayed blocked forever.
Instead, this is the output I get in the console:
Thread1 calling a()
called in method a(): lock()
called in method a(): await()
Thread2 calling b()
called in method b(): lock()
called in method b(): signalAll()
called in method a(): unlock()
called in method b(): unlock()
What am I misunderstanding about the proper use and functioning of lock() and unlock()?
You're not misunderstanding ReentrantLock
, you're misunderstanding Condition
. A Condition
is bound to a lock and Condition.await()
will effectively unlock, check and wait, and then relock the lock. See Condition.await()
.
In a()
, between lock()
and the call to await()
, and between the return of await()
and unlock()
, your lock is behaving as you expect. Inside the call to await()
, the Condition
is managing it.
This is part of the general concept of a "condition variable"; it's why any thread library you find associates a lock of some sort with a condition (e.g. in POSIX C, pthread_cond_wait
requires both a condition variable and a mutex).
Check out the Wikipedia article on condition variables, it explains this behavior and the reasons for it in detail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With