(Translated by https://www.hiragana.jp/)
Reentrant Lock in Java - GeeksforGeeks
Open In App

Reentrant Lock in Java

Last Updated : 14 Mar, 2024
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Save
Share
Report
News Follow

Background

The traditional way to achieve thread synchronization in Java is by the use of synchronized keyword. While it provides a certain basic synchronization, the synchronized keyword is quite rigid in its use. For example, a thread can take a lock only once. Synchronized blocks don’t offer any mechanism of a waiting queue and after the exit of one thread, any thread can take the lock. This could lead to starvation of resources for some other thread for a very long period of time. 
Reentrant Locks are provided in Java to provide synchronization with greater flexibility.  

What are Reentrant Locks?

The ReentrantLock class implements the Lock interface and provides synchronization to methods while accessing shared resources. The code which manipulates the shared resource is surrounded by calls to lock and unlock method. This gives a lock to the current working thread and blocks all other threads which are trying to take a lock on the shared resource. 

As the name says, ReentrantLock allows threads to enter into the lock on a resource more than once. When the thread first enters into the lock, a hold count is set to one. Before unlocking the thread can re-enter into lock again and every time hold count is incremented by one. For every unlocks request, hold count is decremented by one and when hold count is 0, the resource is unlocked. 

Reentrant Locks also offer a fairness parameter, by which the lock would abide by the order of the lock request i.e. after a thread unlocks the resource, the lock would go to the thread which has been waiting for the longest time. This fairness mode is set up by passing true to the constructor of the lock. 
These locks are used in the following way:  

Java
public void some_method()
{
        reentrantlock.lock();
        
          try{
            //Do some work
        }
  
        catch(Exception e){
            e.printStackTrace();
        }
  
        finally{
            reentrantlock.unlock();
        }
}


Unlock statement is always called in the finally block to ensure that the lock is released even if an exception is thrown in the method body(try block).

ReentrantLock() Methods 

  • lock(): Call to the lock() method increments the hold count by 1 and gives the lock to the thread if the shared resource is initially free.
  • unlock(): Call to the unlock() method decrements the hold count by 1. When this count reaches zero, the resource is released.
  • tryLock(): If the resource is not held by any other thread, then call to tryLock() returns true and the hold count is incremented by one. If the resource is not free, then the method returns false, and the thread is not blocked, but exits.
  • tryLock(long timeout, TimeUnit unit): As per the method, the thread waits for a certain time period as defined by arguments of the method to acquire the lock on the resource before exiting.
  • lockInterruptibly(): This method acquires the lock if the resource is free while allowing for the thread to be interrupted by some other thread while acquiring the resource. It means that if the current thread is waiting for the lock but some other thread requests the lock, then the current thread will be interrupted and return immediately without acquiring the lock.
  • getHoldCount(): This method returns the count of the number of locks held on the resource.
  • isHeldByCurrentThread(): This method returns true if the lock on the resource is held by the current thread.
  • hasQueuedThread(): This Method Queries whether the given thread is waiting to acquire this lock.
  • isLocked(): Queries if this lock is held by any thread.
  • newCondition(): Returns a Condition instance for use with this Lock instance.

ReentrantLock() Example

In the following tutorial, we will look at a basic example of Reentrant Locks.

Steps to be followed  

1. Create an object of ReentrantLock
2. Create a worker(Runnable Object) to execute and pass the lock to the object
3. Use the lock() method to acquire the lock on shared resource
4. After completing work, call unlock() method to release the lock

Below is the implementation of problem statement:

Java
// Java code to illustrate Reentrant Locks
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

class worker implements Runnable {
    String name;
    ReentrantLock re;
    public worker(ReentrantLock rl, String n)
    {
        re = rl;
        name = n;
    }
    public void run()
    {
        boolean done = false;
        while (!done) {
            // Getting Outer Lock
            boolean ans = re.tryLock();

            // Returns True if lock is free
            if (ans) {
                try {
                    Date d = new Date();
                    SimpleDateFormat ft
                        = new SimpleDateFormat("hh:mm:ss");
                    System.out.println(
                        "task name - " + name
                        + " outer lock acquired at "
                        + ft.format(d)
                        + " Doing outer work");
                    Thread.sleep(1500);

                    // Getting Inner Lock
                    re.lock();
                    try {
                        d = new Date();
                        ft = new SimpleDateFormat(
                            "hh:mm:ss");
                        System.out.println(
                            "task name - " + name
                            + " inner lock acquired at "
                            + ft.format(d)
                            + " Doing inner work");
                        System.out.println(
                            "Lock Hold Count - "
                            + re.getHoldCount());
                        Thread.sleep(1500);
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    finally {
                        // Inner lock release
                        System.out.println(
                            "task name - " + name
                            + " releasing inner lock");

                        re.unlock();
                    }
                    System.out.println("Lock Hold Count - "
                                       + re.getHoldCount());
                    System.out.println("task name - " + name
                                       + " work done");

                    done = true;
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                finally {
                    // Outer lock release
                    System.out.println(
                        "task name - " + name
                        + " releasing outer lock");

                    re.unlock();
                    System.out.println("Lock Hold Count - "
                                       + re.getHoldCount());
                }
            }
            else {
                System.out.println("task name - " + name
                                   + " waiting for lock");
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public class test {
    static final int MAX_T = 2;
    public static void main(String[] args)
    {
        ReentrantLock rel = new ReentrantLock();
        ExecutorService pool
            = Executors.newFixedThreadPool(MAX_T);
        Runnable w1 = new worker(rel, "Job1");
        Runnable w2 = new worker(rel, "Job2");
        Runnable w3 = new worker(rel, "Job3");
        Runnable w4 = new worker(rel, "Job4");
        pool.execute(w1);
        pool.execute(w2);
        pool.execute(w3);
        pool.execute(w4);
        pool.shutdown();
    }
}

Sample Execution 

Output:
task name - Job2 waiting for lock
task name - Job1 outer lock acquired at 09:49:42 Doing outer work
task name - Job2 waiting for lock
task name - Job1 inner lock acquired at 09:49:44 Doing inner work
Lock Hold Count - 2
task name - Job2 waiting for lock
task name - Job2 waiting for lock
task name - Job1 releasing inner lock
Lock Hold Count - 1
task name - Job1 work done
task name - Job1 releasing outer lock
Lock Hold Count - 0
task name - Job3 outer lock acquired at 09:49:45 Doing outer work
task name - Job2 waiting for lock
task name - Job3 inner lock acquired at 09:49:47 Doing inner work
Lock Hold Count - 2
task name - Job2 waiting for lock
task name - Job2 waiting for lock
task name - Job3 releasing inner lock
Lock Hold Count - 1
task name - Job3 work done
task name - Job3 releasing outer lock
Lock Hold Count - 0
task name - Job4 outer lock acquired at 09:49:48 Doing outer work
task name - Job2 waiting for lock
task name - Job4 inner lock acquired at 09:49:50 Doing inner work
Lock Hold Count - 2
task name - Job2 waiting for lock
task name - Job2 waiting for lock
task name - Job4 releasing inner lock
Lock Hold Count - 1
task name - Job4 work done
task name - Job4 releasing outer lock
Lock Hold Count - 0
task name - Job2 outer lock acquired at 09:49:52 Doing outer work
task name - Job2 inner lock acquired at 09:49:53 Doing inner work
Lock Hold Count - 2
task name - Job2 releasing inner lock
Lock Hold Count - 1
task name - Job2 work done
task name - Job2 releasing outer lock
Lock Hold Count - 0


Important Points  

  1. One can forget to call the unlock() method in the finally block leading to bugs in the program. Ensure that the lock is released before the thread exits.
  2. The fairness parameter used to construct the lock object decreases the throughput of the program.

The ReentrantLock is a better replacement for synchronization, which offers many features not provided by synchronized. However, the existence of these obvious benefits are not a good enough reason to always prefer ReentrantLock to synchronize. Instead, make the decision on the basis of whether you need the flexibility offered by a ReentrantLock.

ReentrantLock() Example With Condition :

We will explore the utilization of the Condition object to pause a thread using the await() method, and the signal() method to resume the thread that was paused using that condition.

Java
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class EvenOddThreadCondition extends Thread {
    ReentrantLock lock = new ReentrantLock();

    Condition even = lock.newCondition();
    Condition odd = lock.newCondition();
    int t;
    EvenOddThreadCondition(int t) {
        this.t=t;
    }

    EvenOddThreadCondition() {
        this.t=0;
    }
    int MAX_COUNT = 10;
    public void run() {
        while (t <= MAX_COUNT) {
            lock.lock();
            try {
                if (t % 2 == 1 && Thread.currentThread().getName().equals("even")) {
                    even.await();
                } else if (t % 2 == 0 && Thread.currentThread().getName().equals("odd")) {
                    odd.await();
                } else {
                    System.out.println(Thread.currentThread().getName() + " Thread " + t);
                    t+=1;
                    if (t % 2 == 0) {
                        even.signal();
                    } else if (t % 2 == 1) {
                        odd.signal();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        EvenOddThreadCondition obj = new EvenOddThreadCondition(5);
        Thread even = new Thread(obj, "even");
        Thread odd = new Thread(obj, "odd");
        even.start();
        odd.start();
    }
}

Output
odd Thread 5
even Thread 6
odd Thread 7
even Thread 8
odd Thread 9
even Thread 10




Explanation of the above Program:

In the provided code, I ensure that even threads utilize an even Condition object to wait using the await() method, and odd threads use an odd condition to wait using await() methods. When the shared resource (t) is even, I release the even thread using the signal() method because the last printed value is an odd value generated by the odd thread. Likewise, when the shared resource(t) is odd, I release the odd thread using the signal() method because the last printed value is an even value produced by the even thread.

Important Point

  1. The thread utilizing the condition to await with await() should avoid signaling through the same condition using the signal() method. Ex: even thread uses even condition to wait with await() and same thread should not do signal with signal() of even condition.
  2. The await() and signal() are similar to wait() and notify() in synchronized block


Previous Article
Next Article

Similar Reads

Object Level Lock vs Class Level Lock in Java
Synchronized is the modifier applicable only for methods and blocks but not for classes and variables. If multiple threads are trying to operate simultaneously on the same java object then there may be a chance of data inconsistency problem to overcome this problem we should go for a 'synchronized' keyword. If a method or block declares as synchron
6 min read
Lock framework vs Thread synchronization in Java
Thread synchronization mechanism can be achieved using Lock framework, which is present in java.util.concurrent package. Lock framework works like synchronized blocks except locks can be more sophisticated than Java’s synchronized blocks. Locks allow more flexible structuring of synchronized code. This new approach was introduced in Java 5 to tackl
5 min read
AtomicInteger for Lock Free Algorithms in Java
Lock-Free Algorithms is one of the mechanisms in which thread-safe access to shared data is possible without the use of Synchronization primitives like mutexes. Multi-threaded applications have shared resources that may be passed among different threads used in the application. This poses the threat of race conditions and data races among the threa
5 min read
Lock Free Stack using Java
In a multi-threaded environment, the lock-free algorithms provide a way in which threads can access the shared resources without the complexity of Locks and without blocking the threads forever. These algorithms become a programmer’s choice as they provide higher throughput and prevent deadlocks. This is mainly because designing lock-based algorith
8 min read
What is Lock Striping in Java Concurrency?
Lock striping is where the locking happens on a few containers or stripes or buckets, implying that getting to a pail just bolts that can and not the whole information structure. That is the idea of lock striping. Having separate locks for a bit of an information structure where each lock is locking on a variable measured arrangement of autonomous
2 min read
Class Level Lock in Java
Every class in Java has a unique lock which is nothing but class level lock. If a thread wants to execute a static synchronized method, then the thread requires a class level lock. Class level lock prevents multiple threads to enter a synchronized block in any of all available instances of the class on runtime. This means if in runtime there are 10
5 min read
Difference Between Lock and Monitor in Java Concurrency
Java Concurrency basically deals with concepts like multithreading and other concurrent operations. This is done to ensure maximum and efficient utilization of CPU performance thereby reducing its idle time in general. Locks have been in existence to implement multithreading much before the monitors have come to usage. Back then locks (or mutex) we
5 min read
Which Method Should We Use to Release a Lock from a Thread in Java?
In JVM we have the option of multithreading. It is an act of executing a complex process using virtual processing entities independent of each other. These entities are called threads. A thread gets blocked if it can't get access to the synchronized block. The Lock API provides the tryLock() method. The thread acquires a lock only if it's available
5 min read
Object Level Lock in Java
Every object in Java has a unique lock. Whenever we are using a synchronized keyword, then only the lock concept will come into the picture. An object-level lock is a mechanism when we want to synchronize a non-static method or non-static code block such that only one thread will be able to execute the code block on a given instance of the class. I
3 min read
Difference Between java.sql.Time, java.sql.Timestamp and java.sql.Date in Java
Across the software projects, we are using java.sql.Time, java.sql.Timestamp and java.sql.Date in many instances. Whenever the java application interacts with the database, we should use these instead of java.util.Date. The reason is JDBC i.e. java database connectivity uses these to identify SQL Date and Timestamp. Here let us see the differences
7 min read
Java AWT vs Java Swing vs Java FX
Java's UI frameworks include Java AWT, Java Swing, and JavaFX. This plays a very important role in creating the user experience of Java applications. These frameworks provide a range of tools and components for creating graphical user interfaces (GUIs) that are not only functional but also visually appealing. As a Java developer, selecting the righ
11 min read
Java.io.ObjectInputStream Class in Java | Set 2
Java.io.ObjectInputStream Class in Java | Set 1 Note : Java codes mentioned in this article won't run on Online IDE as the file used in the code doesn't exists online. So, to verify the working of the codes, you can copy them to your System and can run it over there. More Methods of ObjectInputStream Class : defaultReadObject() : java.io.ObjectInpu
6 min read
Java.lang.Class class in Java | Set 1
Java provides a class with name Class in java.lang package. Instances of the class Class represent classes and interfaces in a running Java application. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects. It has no public constructor. Class objects are cons
15+ min read
Java.lang.StrictMath class in Java | Set 2
Java.lang.StrictMath Class in Java | Set 1More methods of java.lang.StrictMath class 13. exp() : java.lang.StrictMath.exp(double arg) method returns the Euler’s number raised to the power of double argument. Important cases: Result is NaN, if argument is NaN.Result is +ve infinity, if the argument is +ve infinity.Result is +ve zero, if argument is
6 min read
java.lang.instrument.ClassDefinition Class in Java
This class is used to bind together the supplied class and class file bytes in a single ClassDefinition object. These class provide methods to extract information about the type of class and class file bytes of an object. This class is a subclass of java.lang.Object class. Class declaration: public final class ClassDefinition extends ObjectConstruc
2 min read
Java.util.TreeMap.pollFirstEntry() and pollLastEntry() in Java
Java.util.TreeMap also contains functions that support retrieval and deletion at both, high and low end of values and hence give a lot of flexibility in applicability and daily use. This function is poll() and has 2 variants discussed in this article. 1. pollFirstEntry() : It removes and retrieves a key-value pair with the least key value in the ma
4 min read
Java.util.TreeMap.floorEntry() and floorKey() in Java
Finding greatest number less than given value is used in many a places and having that feature in a map based container is always a plus. Java.util.TreeMap also offers this functionality using floor() function. There are 2 variants, both are discussed below. 1. floorEntry() : It returns a key-value mapping associated with the greatest key less than
3 min read
java.lang.Math.atan2() in Java
atan2() is an inbuilt method in Java that is used to return the theta component from the polar coordinate. The atan2() method returns a numeric value between -[Tex]\pi [/Tex]and [Tex]\pi [/Tex]representing the angle [Tex]\theta [/Tex]of a (x, y) point and the positive x-axis. It is the counterclockwise angle, measured in radian, between the positiv
1 min read
java.net.URLConnection Class in Java
URLConnection Class in Java is an abstract class that represents a connection of a resource as specified by the corresponding URL. It is imported by the java.net package. The URLConnection class is utilized for serving two different yet related purposes, Firstly it provides control on interaction with a server(especially an HTTP server) than URL cl
5 min read
Java 8 | ArrayDeque removeIf() method in Java with Examples
The removeIf() method of ArrayDeque is used to remove all those elements from ArrayDeque which satisfies a given predicate filter condition passed as a parameter to the method. This method returns true if some element are removed from the Vector. Java 8 has an important in-built functional interface which is Predicate. Predicate, or a condition che
3 min read
Java.util.GregorianCalendar Class in Java
Prerequisites : java.util.Locale, java.util.TimeZone, Calendar.get()GregorianCalendar is a concrete subclass(one which has implementation of all of its inherited members either from interface or abstract class) of a Calendar that implements the most widely used Gregorian Calendar with which we are familiar. java.util.GregorianCalendar vs java.util.
10 min read
Java lang.Long.lowestOneBit() method in Java with Examples
java.lang.Long.lowestOneBit() is a built-in method in Java which first convert the number to Binary, then it looks for first set bit present at the lowest position then it reset rest of the bits and then returns the value. In simple language, if the binary expression of a number contains a minimum of a single set bit, it returns 2^(first set bit po
3 min read
Java Swing | Translucent and shaped Window in Java
Java provides different functions by which we can control the translucency of the window or the frame. To control the opacity of the frame must not be decorated. Opacity of a frame is the measure of the translucency of the frame or component. In Java, we can create shaped windows by two ways first by using the AWTUtilities which is a part of com.su
5 min read
Java lang.Long.numberOfTrailingZeros() method in Java with Examples
java.lang.Long.numberOfTrailingZeros() is a built-in function in Java which returns the number of trailing zero bits to the right of the lowest order set bit. In simple terms, it returns the (position-1) where position refers to the first set bit from the right. If the number does not contain any set bit(in other words, if the number is zero), it r
3 min read
Java lang.Long.numberOfLeadingZeros() method in Java with Examples
java.lang.Long.numberOfLeadingZeros() is a built-in function in Java which returns the number of leading zero bits to the left of the highest order set bit. In simple terms, it returns the (64-position) where position refers to the highest order set bit from the right. If the number does not contain any set bit(in other words, if the number is zero
3 min read
Java lang.Long.highestOneBit() method in Java with Examples
java.lang.Long.highestOneBit() is a built-in method in Java which first convert the number to Binary, then it looks for the first set bit from the left, then it reset rest of the bits and then returns the value. In simple language, if the binary expression of a number contains a minimum of a single set bit, it returns 2^(last set bit position from
3 min read
Java lang.Long.byteValue() method in Java with Examples
java.lang.Long.byteValue() is a built-in function in Java that returns the value of this Long as a byte. Syntax: public byte byteValue() Parameters: The function does not accept any parameter. Return : This method returns the numeric value represented by this object after conversion to byte type. Examples: Input : 12 Output : 12 Input : 1023 Output
3 min read
Java lang.Long.reverse() method in Java with Examples
java.lang.Long.reverse() is a built-in function in Java which returns the value obtained by reversing the order of the bits in the two's complement binary representation of the specified long value. Syntax: public static long reverse(long num) Parameter : num - the number passed Returns : the value obtained by reversing the order of the bits in the
2 min read
java.lang.reflect.Proxy Class in Java
A proxy class is present in java.lang package. A proxy class has certain methods which are used for creating dynamic proxy classes and instances, and all the classes created by those methods act as subclasses for this proxy class. Class declaration: public class Proxy extends Object implements SerializableFields: protected InvocationHandler hIt han
4 min read
Java.math.BigInteger.modInverse() method in Java
Prerequisite : BigInteger Basics The modInverse() method returns modular multiplicative inverse of this, mod m. This method throws an ArithmeticException if m <= 0 or this has no multiplicative inverse mod m (i.e., gcd(this, m) != 1). Syntax: public BigInteger modInverse(BigInteger m) Parameters: m - the modulus. Return Value: This method return
2 min read
Article Tags :
Practice Tags :
three90RightbarBannerImg