Search code examples
javareentrantlock

Renentrant tryLock() not locking in multi threaded enviroment


This is regarding tryLock() method in re entrant locks. I am running the below sample code. I understand that this code will run into a deadlock.

import java.util.concurrent.locks.ReentrantLock;
public class TestMain {
    public static void main(String[] args) {
        ReentrantLock rl=new ReentrantLock();
        S t1=new S(rl);
        S t2=new S(rl);
        Thread t=new Thread(t1);
        Thread u=new Thread(t2);
        t.start();
        u.start();
    }
}
class S extends Thread{
    ReentrantLock rl;
    S(ReentrantLock r){
        rl=r;
    }
    public void run(){
        System.out.println("Entry--");
        rl.tryLock();
        System.out.println("locked1 "+rl.getHoldCount()+" "+Thread.currentThread().getName());
        rl.lock();
        System.out.println("locked2 "+rl.getHoldCount()+" "+Thread.currentThread().getName());
        rl.unlock();
        System.out.println("unlocked "+rl.getHoldCount()+" "+Thread.currentThread().getName());
    }
}

But here my question is that why the statement after the rl.tryLock() statement is running for the second thread also. Output is coming as

Entry--
Entry--
locked1 0 Thread-3
locked1 1 Thread-2
locked2 2 Thread-2
unlocked 1 Thread-2

I don't think this line should ever have been printed

"locked2 2 Thread-2"

Solution

  • Like lock, tryLock must also be paired with an unlock IF it returns true. When using tryLock you MUST check the return value and unlock if it was locked, because otherwise it will never be fully unlocked.

    When it prints the following sequence occurs: [Note this is a possible sequence, between 5 and 8 can be re-arranged because multiple threads are involved and it'll still be correct]

    1. [Thread-2] System.out.println("Entry--");
    2. [Thread-3] System.out.println("Entry--");
    3. [Thread-2] rl.tryLock(); [r1 now locked to Thread-2, count=1]
    4. [Thread-3] rl.tryLock(); [r1 already locked, returns false]
    5. [Thread-3] System.out.println("locked1 "+rl.getHoldCount()+" "+Thread.currentThread().getName()); [r1 not held, count is thus 0]
    6. [Thread-2] System.out.println("locked1 "+rl.getHoldCount()+" "+Thread.currentThread().getName()); [r1 held, count=1]
    7. [Thread-3] rl.lock(); [r1 already locked, blocks]
    8. [Thread-2] r1.lock(); [r1 held, count=2]
    9. [Thread-2] System.out.println("locked2 "+rl.getHoldCount()+" "+Thread.currentThread().getName());
    10. [Thread-2] rl.unlock(); [r1 held, count=1]
    11. [Thread-2] System.out.println("unlocked "+rl.getHoldCount()+" "+Thread.currentThread().getName());

    The line "locked2 2 Thread-2" is printed because a re-entrant lock can be locked more than once if locked by the holder. So both tryLock and lock succeed, but you unlock only one of them, so the other thread blocks forever.