Skip to main content

Reentrant Locks




Synchronized uses intrinsic locks or monitors. Every object in Java has an intrinsic lock associated with it. Whenever a thread tries to access a synchronized block or method, it acquires the intrinsic lock or the monitor on that object. In the case of static methods, the thread acquires the lock over the class object.


ReentrantLock is an explicit locking mechanism.  A reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with following extended capabilities.


Polled and Timed Lock Acquisition

Lock.tryLock() is polled lock acquisition mechanism and tryLock(long timeout, TimeUnit unit) is timed lock acquisition mechanism. tryLock() will return immediately. If no other thread locked, then it will return true else returns false. The tryLock(long timeout, TimeUnit unit) will wait for the timeout period to acquire the lock if the lock is not available until timeout period it returns with false similar to tryLock(). In timed tryLock, when the current thread is waiting for timeout duration for acquiring the lock, meanwhile if another thread interrupts it, it will come out of lock acquisition by an InterruptedException. tryLock(long timeout, TimeUnit unit) behavior is same as lock.lockInterruptibly() for the duration of the timeout when it is waiting for the lock, ie., if another thread interrupts, it will come out lock acquisition attempt.


Interruptible Lock Acquisition

Lock.lockInterruptibly() is similar to lock() but it can be interrupted by another thread. The ReentrantLock.lock() is a blocking call in an attempt to acquire the lock, but lockInterruptibly() is non-blocking call, another thread can interrupt it from indefinitely waiting for acquiring the lock. In a way, ReentrantLock.lock() is same as the implicitly synchronized lock.


Non-block Structured Locking

The synchronized block (intrinsic lock) must be fully contained within a single method. A Lock can have it’s calls to lock() and unlock() in separate methods. In intrinsic locks, acquire-release pairs are block-structured. In other words, a lock is always released in the same basic block in which it was acquired, regardless of how control exits the block. Extrinsic locks allow the facility to have more explicit control.


Fairness

The ReentrantLock constructor offers a choice of two fairness options: create a non-fair lock or a fair lock. With fair locking, threads can acquire locks only in the order in which they were requested, whereas an unfair lock allows a lock to acquire it out of its turn. This is called barging.


The ReentrantLock has following four methods to acquire the lock.


lock() : this un-interruptible similar to intrinsic locking mechanism provided by synchronized methods or blocks. The uninterruptible lock will block when lock.lock() gets called until the thread that currently owns the lock releases it. If the thread that currently owns the lock never releases it then this thread can't get the lock and will be blocked forever. This is analogous to the normal operation of the synchronized (object) { } block. The method will block while trying to get a lock on the object when it does it proceeds.


tryLock() : this is polled mechanism and non-blocking call. It checks if the lock is available, and if not available immediately returns with false and proceeds.


tryLock(long timeout, TimeUnit unit) : this is interruptible method. If the lock is not available, then it will wait for timeout duration to get the lock, meanwhile, if some other thread interrupts, it will come out of lock acquisition mechanism by InterruptedException and will not proceed like tryLock().

lockInterruptibly() : this is also interruptible method similar to tryLock(long timeout, TimeUnit unit) but without timeout.

In addition to above methods, the ReentrantLock has several other methods to see the number of threads waiting to acquire this lock and to query the number of holds on this lock by the current thread etc.,

Comments

Popular posts from this blog

Find second largest element in an array

Find second largest element in an unsorted array.               We can reach the solution in three ways.  Solution 1 Sort the array and return last but one element. We could use already existing sorting methods in JDK Arrays class and sort the array. public static int findSecondLargestV1( int [] array ){ if ( array . length == 0 || array . length < 2){ return -1; } Arrays.sort( array ); return array [ array . length - 2]; } Complexity: Since this solution depends on sorting, the complexity is equal to complexity of sorting algorithm, ie., O(n log n) Solution 2 public static int findSecondLargestV2( int [] array ){ if ( array . length == 0 || array . length < 2){ return -1; } int max = -1; for ( int i = 0; i < array . length ; i ++){ if ( array [ i ] > max ){ max = array [ i ]; } } int secondMax = -1; for (

Merge two sorted Lists or Arrays

Code to merge two array lists: public static ArrayList<Integer> mergeLists(ArrayList<Integer> l1 , ArrayList<Integer> l2 ){ ArrayList<Integer> l3 = new ArrayList<Integer>(); int i = 0; int j = 0; while ( i < ( l1 .size()) && j < ( l2 .size())){ if ( l1 .get( i ) < l2 .get( j )){ l3 .add( l1 .get( i )); i ++; } else { l3 .add( l2 .get( j )); j ++; } } if ( i < l1 .size()){ while ( i < l1 .size()){ l3 .add( l1 .get( i )); i ++; } } else if ( j < l2 .size()){ while ( j < l2 .size()){ l3 .add( l2 .get( j )); j ++; } } return l3 ; } Code to merge two arrays: public static int[] mergeArrays(int[] a, int[] b){ if((a == null || a.length == 0) && (b == null || b.length == 0)) return new int[0]; if((a == null || a.length == 0)) return b; if(b == n

Binary search (recursive and non-recursive)

Recursive solution: public static int binarySearch( int [] array , int startIndex , int endIndex , int value ){ int midIndex = ( startIndex + endIndex )/2; if ( array [ midIndex ] == value ){ return value ; } if ( startIndex > endIndex ){ return -1; } if ( value < array [ midIndex ]){ int sI = startIndex ; int eI = midIndex - 1; return binarySearch( array , sI , eI , value ); } else { int sI = midIndex + 1; int eI = endIndex ; return binarySearch( array , sI , eI , value ); } } Non-Recursive solution: public static int binarySearchNoRecursion( int [] array ,  int value ){ int startIndex = 0; int endIndex = array . length - 1; while ( startIndex <= endIndex ){ int midIndex = ( startIndex + endIndex )/2; if ( array [ midIndex ] == value ){ return value ; } if ( value < ar