Home » Core Java » util » concurrent » locks » ReentrantLock » Java ReentrantLock Example

About Chandan Singh

Chandan Singh
Chandan holds a degree in Computer Engineering and is a passionate software programmer. He has good experience in Java/J2EE Web-Application development for Banking and E-Commerce Domains.

Java ReentrantLock Example

In this example, we shall be demonstrating how to use ReentrantLock in Java.

Rigidness of Intrinsic Locking :

The traditional way of providing synchronization in multi-threaded environment was to use the synchronized keyword. However, the synchronized keyword is considered rather rigid under certain circumstances.For example, if a thread is already executing inside a synchronized block and another thread tries to enter the block, it has to wait until the currently running thread exits the block. As long as the thread does not enter the synchronized block it remains blocked and cannot be interrupted.

Any thread can acquire the lock once the synchronized thread is exited by a currently running thread. This may lead to starvation of some(unlucky?) thread.
Synchronized blocks don’t offer any mechanism to query the status of “waiting queue” of threads for a particular resource.

The synchronized block have to be present within the same method. A synchronized block cannot start in one method and end in another.

ReentrantLock to the Rescue!

While every application does not need the flexibility discussed above, it is certainly worth looking into how we can design a more flexible application using the ReentrantLock Class.

The ReentrantLock was provided in the java.util.concurrent.locks package since JDK 1.5, which provides extrinsic locking mechanism.
ReentrantLock Class provides a constructor that optionally takes a boolean parameter fair. When more than one thread are competing for the same lock, the lock favors granting access to the longest waiting thread.(The reader should not misunderstand this as a means to guarantee fairness in Thread scheduling.)

ReentrantLock Class provides a number of ways to acquire locks. The tryLock() and the tryLock(long timeout, TimeUnit unit) methods provide means for the threads to time-out while waiting for a lock instead of indefinitely waiting till lock is acquired.

try{
     lock.tryLock(300,TimeUnit.SECONDS);
   }
catch(InterruptedException ie)
   {
     ...
   }

It also provides us methods which provide information about list of Threads waiting for acquiring the lock and are queued.

Also, the lockInterruptibly() method provides the mechanism to interrupt a thread while it has acquired the lock. This method however, throws InterruptedException if the thread is still waiting for the lock.

Let’s have a look at a sample program using ReentrantLock.

ThreadSafeArrayList.java:

package com.jcg.examples;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ThreadSafeArrayList<E>
{
	private final Lock lock = new ReentrantLock();

	private final List<E> list = new ArrayList<E>();

	private static int i = 0;

	public void set(E o)
	{
			lock.lock();

			try
			{
				i++;
				list.add(o);
				System.out.println("Adding element by thread"+Thread.currentThread().getName());
			}
			finally
			{
				lock.unlock();
			}
	}

	public static void main(String[] args)
	{

			final ThreadSafeArrayList<String> lockExample = new ThreadSafeArrayList<String>();
			Runnable syncThread = new Runnable()
			{

				@Override
				public void run()
					{
						while (i < 6)
						{
							lockExample.set(String.valueOf(i));
									
							try
							{
								Thread.sleep(100);
							}
							catch (InterruptedException e)
							{
								e.printStackTrace();
							}
						}
					}
			};
			Runnable lockingThread = new Runnable()
			{

				@Override
				public void run()
					{
						while (i < 6)
						{
							lockExample.set(String.valueOf(i));
							try
							{
								Thread.sleep(100);
							}
							catch (InterruptedException e)
							{
								e.printStackTrace();
							}
						}
					}
			};
			Thread t1 = new Thread(syncThread, "syncThread");
			Thread t2 = new Thread(lockingThread, "lockingThread");
			t1.start();
			t2.start();
	}
}

Output :

Adding element by threadsyncThread
Adding element by threadlockingThread
Adding element by threadlockingThread
Adding element by threadsyncThread
Adding element by threadlockingThread
Adding element by threadsyncThread

Down-sides with ReentrantLock

While ReentrantLock Class does provide a lot of flexibility and control it does carry some baggage.

  • A careless developer can easily forget to release a lock acquired and that will introduce subtle bugs into the software which are a bit difficult to debug.
  • The code using normal synchronized block is far more readable than a corresponding code using ReentrantLock.
  • The fairness parameter used to construct the ReentrantLock object can reduce the throughput of the program

Conclusion :

While the ReentrantLock requires a little more expertise and carefulness on the part of the programmer, the flexibility and control offered by it, is certainly worth the effort.

(No Ratings Yet)
Start the discussion Views Tweet it!

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

 

Leave a Reply

avatar
  Subscribe  
Notify of