4

I was studying reentrant locking in Java. Need certain clarification on this concept that how actually it works. What all I understand for below snippet :

class Test{
    public synchronized a(){   
       some code;
      b();
       some code;
    }
    public synchronized b(){    
       some code;
    }

}

Above code has this scenario of reentrant lock issue.

What I understand here is, suppose we had Two Threads: T1 and T2 in application executing on Test shared object.

Whoever T1 or T2 acquires lock acquire on both a() and b(). Let say T1 first and executing a(). While execution of a() control reaches to b(); call. Now in that case T1 expecting a new Lock for this b(), or since it already had lock over b() so locking is skipped.

Need help with detailed explanation of this behavior along with issue in above code . Also how reentrant locking mechanism will help here along with snippet and detailed explanation for that as well.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
Neeraj
  • 171
  • 2
  • 11

2 Answers2

6

A reentrant lock is one that allows a thread to acquire the lock again (many times) when it already holds the lock.

For example, if thread T1 calls a() on an object, the a() method acquires the lock on the object, and starts executing the body. When the body of a calls b(), the b() call "reentrantly" acquires the same lock. When the b() call returns, the a() call is still holding the lock. The lock is only released when the a() call returns.

(Hypothetically, if Java primitive locks were not reentrant, then the sequence T1 calls a() which then calls b() would probably either deadlock, or throw an exception ...)

Reentrant locks are typically implemented with a reference count which tells the locking implementation how deep the reentrancy is.

See also: https://stackoverflow.com/a/16504266/139985

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
2

If the lock wasn't re-entrant, the thread wouldn't be able to call b() while holding the lock it acquired when entering a().

When a() is called, and it call b() you need a lock which is reentrant or the thread will live lock itself try to acquire the lock a second time. Instead of trying to get the lock again, it instead recognises it already has a lock increments a counter so that when b() exists, it doesn't release the lock but instead decrements the counter.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Peter, can you please elaborate the First statement again "If the lock wasn't re-entrant, the thread wouldn't be able to call b() while holding the lock it acquired when entering a()." .... – Neeraj Oct 27 '18 at 12:02
  • @Neeraj when a lock is non-reentrant, you can't acquire a lock on something even if you already hold it. Methods can also be non-reentrant which means they cannot be called again while inside that method. – Peter Lawrey Oct 27 '18 at 12:47
  • OK I got this. But @Peter my next doubt is Since In Java through Synchronized we acquires Intrinsic locks. And Intrinsic locks are by default ReEntrant in nature. Utility of Reentrant which I understand from your explanation is that it helps in acquiring same lock over resource if requires. Then what is utility of ReentrantLock class in java because We already acquire Reentrant locks through Synchronization mechanism. I mean what is the best way either to go with ReEntrantLock class Synchronization and why . Kindly help . – Neeraj Oct 28 '18 at 07:13
  • @Neeraj A `ReentrantLock` has additional functionality you can't achieve with `synchronized` e.g. tryLock, fair locking. If you don't need this additional functionality I suggest you use plain synchronized. – Peter Lawrey Oct 29 '18 at 09:59