Saturday, November 13, 2021

Difference Between ReentrantLock and Synchronized in Java

From Java 5 new lock implementations have been provided like ReentrantLock, ReentrantReadWriteLock which provide more extensive locking operations than can be obtained using synchronized methods and statements. In this post we'll see in detail what extended functionality is provided by ReentrantLock and what are the differences between ReentrantLock and synchronized in Java.

According to the Java docs

"ReentrantLock is 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 extended capabilities."

ReentrantLock Vs Synchronized in Java

  1. When you use a synchronized block or method you just need to write synchronized keyword (and provide associated object) acquiring lock and releasing it is done implicitly.
    With ReentrantLock acquiring and releasing lock is done by user using lock() and unlock() methods.
  2. Prescribed way to use RentrantLock in Java is to use a try-finally block. Call to lock should immediately be followed with a try block and lock should be released in finally block. That way lock will be released even if exception is thrown in critical section code.

    lock.lock();
    try {    
      //…method body    
    }finally {
      lock.unlock();
    }
     
    With Synchronized there is no such compulsion as acquiring and releasing is done implicitly.
    Synchronized(myObj){
      …
      …
    }
     
    Thus making the code written with Synchronized much cleaner and easy to read.
  3. Synchronized keyword forces all lock acquisitions and releases to occur in a block-structured way which means when multiple locks are acquired they must be released in the opposite order, and all locks must be released in the same lexical scope in which they were acquired.

    ReentrantLock provides more flexibility, it allows a lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order.

    With ReentrantLock the below code is possible but not with synchronized.
    private ReentrantLock lock;
    public void methodA() {
      ...
      lock.lock();
      ...
    }
    
    public void methodB() {
      ...
      lock.unlock();
      ...
    }
    
  4. ReentrantLock provides additional functionality over the use of synchronized methods and statements by providing an option for fairness, providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).
    • Fairness- ReentrantLock class in Java has one constructor which takes boolean value as an argument. That lets you choose whether you want a fair or an unfair lock depending upon whether the boolean value is true or false. A fair lock is one where the threads acquire the lock in the same order they asked for it; whereas in case of an unfair lock a thread can sometimes acquire a lock before another thread that asked for it first.
      With Synchronized there is no such option.
    • Lock interruptibly- ReentrantLock provides a method lockInterruptibly
      public void lockInterruptibly() throws InterruptedException
      
      Where the thread acquires a lock if it is not interrupted.
    • Ability to check if the lock is being held- ReentrantLock provides ability to check if the lock is already being held using tryLock() method. This provides a non-blocking attempt to acquire a lock for a thread.

      tryLock()- Acquires the lock only if it is not held by another thread at the time of invocation.

      tryLock(long timeout, TimeUnit unit)- Acquires the lock if it is not held by another thread within the given waiting time and the current thread has not been interrupted.

  5. There are some other features provided by ReentrantLock-
    • getHoldCount()- Queries the number of holds on this lock by the current thread.
    • getWaitingThreads(Condition condition)- Returns a collection containing those threads that may be waiting on the given condition associated with this lock.
    • isHeldByCurrentThread()- Queries if this lock is held by the current thread.
    • isLocked()- Queries if this lock is held by any thread.

That's all for this topic Difference Between ReentrantLock and Synchronized in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Java StampedLock With Examples
  2. Callable and Future in Java With Examples
  3. AtomicInteger in Java With Examples
  4. Lock Striping in Java Concurrency
  5. Java Concurrency Interview Questions And Answers

You may also like-

  1. Deadlock in Java Multi-Threading
  2. Java ThreadLocal Class With Examples
  3. How to Sort Elements in Different Order in TreeSet
  4. Optional Class in Java With Examples
  5. Functional Interface Annotation in Java
  6. Interface Static Methods in Java
  7. Method Overriding in Java
  8. Dependency Injection in Spring Framework

2 comments:

  1. Hi Anshudeep,

    Thank you for the food article. But I've a doubt here. If you look at the 2nd difference/point and a statement given in ReentrantLock in Java Concurrency post under Convention while using ReentrantLock in Java subheading you mentioned that "When you are using Reentrantlock in Java, it is a recommended practice to always immediately follow a call to lock with a try block."

    These two statements are contradictory. Please correct me if I'm wrong.

    ReplyDelete
    Replies
    1. Thanks for pointing it out. Sentence was incomplete with the suggestion to use try/finally block but why was missing. Code snippet was also not as per convention.
      That has been corrected and many thanks again for pointing it out.

      Delete