Implementation of custom/own Lock and ReEntrantLock in java


In previous thread concurrency tutorial we learned what is Locks and ReEntrantLocks in java and in this thread concurrency tutorial we will learn what is Custom Lock in java, Custom Lock interface methods and  constructor in java, how to write Custom ReentrantLock’s code in java, Example to demonstrate usage of Custom ReentrantLock, Application of using Custom ReentrantLock with program in java.



Contents of page :
  • Custom Lock in java?
  • Custom Lock interface methods in java >
    • void lock()
    • CODE in thread concurrency in java>
    • void unlock()
    • CODE  in thread concurrency in java>
    • boolean tryLock()
    • CODE  in thread concurrency in java >
  • Custom ReentrantLock class in java >
  • Custom ReentrantLock constructor in java >
    • ReentrantLockCustom()
    • CODE in java >
  • Custom ReentrantLock class methods in java >
  • Custom ReentrantLock’s code in java >
  • Program/ Example to demonstrate usage of Custom ReentrantLock >
  • Let’s discuss output in detail, to get better understanding of Custom ReentrantLock usage in program >
  • Program/ Example to demonstrate usage of Custom ReentrantLock’s tryLock() method  >
  • Let’s discuss output in detail, to get better understanding of Custom ReentrantLock’s tryLock() method usage in program >
  • Application of using Custom ReentrantLock with program >
    • Program to show that with Custom Reentrantlocks no problems will happen when  2 passengers try to book train ticket, when only 1 ticket was available >
  • OUTPUT ANALYZATION of above program >
  • What will happen if thread that holds lock again calls lock() method?
  • Program/ Example to show will happen if thread that holds lock again calls lock() method



Custom Lock in thread concurrency in java?
In previous tutorial we read how to use Locks and ReEntrantLocks in java. In this post we will be implementing custom Locks and ReEntrantLocks. This post intends you give you basic functionality of Locks and ReEntrantLocks using your own java code

The java.util.concurrent.locks.Locks is a  interface and its implementations provide more extensive locking operations than can be obtained using synchronized methods and statements.
A lock helps in controlling access to a shared resource by multiple threads. Only one thread at a time can acquire the lock and access the shared resource.
If a second thread attempts to acquire the lock on shared resource when it is acquired by another thread, the second thread will wait until the lock is released. In this way we can achieve synchronization and race conditions can be avoided.
Read lock of a ReadWriteLock may allow concurrent access to a shared resource.


Custom Lock interface methods in thread concurrency in java >

void lock()
Acquires the lock if it is not held by another thread. And sets lock hold count to 1.
If current thread already holds lock then lock hold count is increased by 1.
If the lock is held by another thread then the current thread waits for another thread to release lock.

CODE in thread concurrency in java >
public synchronized void lock() {
  
   //Acquires the lock if it is not held by another thread.
   // And sets lock hold count to 1.
   if(lockHoldCount==0){
          lockHoldCount++;
          IdOfThreadCurrentlyHoldingLock=Thread.currentThread().getId();
   }
   //If current thread already holds lock then lock hold
   // count is increased by 1.
   else if(lockHoldCount>0
                && IdOfThreadCurrentlyHoldingLock==Thread.currentThread().getId()){
          lockHoldCount++;
   }
   //If the lock is held by another thread then the current
   // thread waits for another thread to release lock.
   else{
          try {
                 wait();
                 lockHoldCount++;
                 IdOfThreadCurrentlyHoldingLock=Thread.currentThread().getId();
          } catch (InterruptedException e) {
                 e.printStackTrace();
          }
   }
}


void unlock()
If the current thread is the holding the lock then the lock hold count is decremented by 1. If the lock hold count has reached 0, then the lock is released.
If lock hold count is still greater than 0 then lock is not released.
If the current thread is not holding the lock then IllegalMonitorStateException is thrown.

CODE in thread concurrency in java >
public synchronized void unlock() {
   //current thread is not holding the lock, throw IllegalMonitorStateException.
   if(lockHoldCount==0)
          throw new IllegalMonitorStateException();
  
   lockHoldCount--; //decrement lock hold count by 1
  
   //if lockHoldCount is 0, lock is released, and
   //one waiting thread is notified.
   if(lockHoldCount==0)
          notify();
}


boolean tryLock()
Acquires the lock if it is not held by another thread and returns true. And sets lock hold count to 1.
If current thread already holds lock then method returns true. And increments lock hold count by 1.
If lock is held by another thread then method return false.

CODE in java >
   public synchronized boolean tryLock(){
          //Acquires the lock if it is not held by another thread and
          //returns true
          if(lockHoldCount==0){
                 lock();
                 return true;
          }
          //If lock is held by another thread then method return false.
          else
                 return false;
   }




Custom ReentrantLock class >
Custom ReentrantLock is a class which implements Custom Lock interface. It provides some additional capabilities as defined in Lock interface.

Custom ReentrantLock constructor >
  • ReentrantLockCustom()
Creates an instance of ReentrantLock.

CODE in thread concurrency in java >
   ReentrantLockCustom(){
          lockHoldCount=0;
   }



Custom ReentrantLock class methods  in java>
Custom ReentrantLock class provides implementation of all Custom Lock interface methods
void lock()
void unlock()
boolean tryLock()



Custom ReentrantLock’s code in java >
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
/**
* Custom Lock interface
*/
interface LockCustom{
   void lock();
   void unlock();
   boolean tryLock();  
}
/**@author AnkitMittal
* Copyright (c), AnkitMittal .
* All Contents are copyrighted and must not be reproduced in any form.
  
* A lock helps in controlling access to a shared resource by multiple threads.
* Only one thread at a time can acquire the lock and access the shared resource.
* If a second thread attempts to acquire the lock on shared resource when it is
* acquired by another thread, the second thread will wait until the lock is released.
* In this way we can achieve synchronization and race conditions can be avoided.
*/
class ReentrantLockCustom implements LockCustom {
   int lockHoldCount;
  
   //Id of thread which is currently holding the lock.
   long IdOfThreadCurrentlyHoldingLock;
  
   /**
   * Creates an instance of ReentrantLock.
   * Initially lock hold count is 0.
   */
   ReentrantLockCustom(){
          lockHoldCount=0;
   }
  
   /**
   * Acquires the lock if it is not held by another thread.
   * And sets lock hold count to 1.
   * If current thread already holds lock then lock hold
   * count is increased by 1.
   * If the lock is held by another thread then the current
   * thread waits for another thread to release lock.
   */
   public synchronized void lock() {
         
          //Acquires the lock if it is not held by another thread.
          // And sets lock hold count to 1.
          if(lockHoldCount==0){
                 lockHoldCount++;
                 IdOfThreadCurrentlyHoldingLock=Thread.currentThread().getId();
          }
          //If current thread already holds lock then lock hold
          // count is increased by 1.
          else if(lockHoldCount>0
                       && IdOfThreadCurrentlyHoldingLock==Thread.currentThread().getId()){
                 lockHoldCount++;
          }
          //If the lock is held by another thread then the current
          // thread waits for another thread to release lock.
          else{
                 try {
                       wait();
                       lockHoldCount++;
                       IdOfThreadCurrentlyHoldingLock=Thread.currentThread().getId();
                 } catch (InterruptedException e) {
                       e.printStackTrace();
                 }
          }
   }
   /**
   * If the current thread is the holding the lock then the lock hold
   * count is decremented by 1. If the lock hold count has reached 0,
   * then the lock is released.
   * If lock hold count is still greater than 0 then lock is not released.
   * If the current thread is not holding the lock then
   * IllegalMonitorStateException is thrown.
   */
   public synchronized void unlock() {
          //current thread is not holding the lock, throw IllegalMonitorStateException.
          if(lockHoldCount==0)
                 throw new IllegalMonitorStateException();
         
          lockHoldCount--; //decrement lock hold count by 1
         
          //if lockHoldCount is 0, lock is released, and
          //one waiting thread is notified.
        if(lockHoldCount==0)
           notify();

   }
  
   /**
   * Acquires the lock if it is not held by another thread and returns
   * true. And sets lock hold count to 1.
   * If current thread already holds lock then method
   * returns true. And increments lock hold count by 1.
   * If lock is held by another thread then method return false.
   */
   public synchronized boolean tryLock(){
          //Acquires the lock if it is not held by another thread and
          //returns true
          if(lockHoldCount==0){
                 lock();
                 return true;
          }
          //If lock is held by another thread then method return false.
          else
                 return false;
   }
}


Program/ Example to demonstrate usage of Custom ReentrantLock in java >
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
/**
* Custom Lock interface
*/
interface LockCustom{
   void lock();
   void unlock();
   boolean tryLock();  
}
/**@author AnkitMittal
* Copyright (c), AnkitMittal .
* All Contents are copyrighted and must not be reproduced in any form.
  
* A lock helps in controlling access to a shared resource by multiple threads.
* Only one thread at a time can acquire the lock and access the shared resource.
* If a second thread attempts to acquire the lock on shared resource when it is
* acquired by another thread, the second thread will wait until the lock is released.
* In this way we can achieve synchronization and race conditions can be avoided.
*/
class ReentrantLockCustom implements LockCustom {
   int lockHoldCount;
  
   //Id of thread which is currently holding the lock.
   long IdOfThreadCurrentlyHoldingLock;
  
   /**
   * Creates an instance of ReentrantLock.
   * Initially lock hold count is 0.
   */
   ReentrantLockCustom(){
          lockHoldCount=0;
   }
  
   /**
   * Acquires the lock if it is not held by another thread.
   * And sets lock hold count to 1.
   * If current thread already holds lock then lock hold
   * count is increased by 1.
   * If the lock is held by another thread then the current
   * thread waits for another thread to release lock.
   */
   public synchronized void lock() {
         
          //Acquires the lock if it is not held by another thread.
          // And sets lock hold count to 1.
          if(lockHoldCount==0){
                 lockHoldCount++;
                 IdOfThreadCurrentlyHoldingLock=Thread.currentThread().getId();
          }
          //If current thread already holds lock then lock hold
          // count is increased by 1.
          else if(lockHoldCount>0
                       && IdOfThreadCurrentlyHoldingLock==Thread.currentThread().getId()){
                 lockHoldCount++;
          }
          //If the lock is held by another thread then the current
          // thread waits for another thread to release lock.
          else{
                 try {
                       wait();
                       lockHoldCount++;
                       IdOfThreadCurrentlyHoldingLock=Thread.currentThread().getId();
                 } catch (InterruptedException e) {
                       e.printStackTrace();
                 }
          }
   }
   /**
   * If the current thread is the holding the lock then the lock hold
   * count is decremented by 1. If the lock hold count has reached 0,
   * then the lock is released.
   * If lock hold count is still greater than 0 then lock is not released.
   * If the current thread is not holding the lock then
   * IllegalMonitorStateException is thrown.
   */
   public synchronized void unlock() {
          //current thread is not holding the lock, throw IllegalMonitorStateException.
          if(lockHoldCount==0)
                 throw new IllegalMonitorStateException();
         
          lockHoldCount--; //decrement lock hold count by 1
         
          //if lockHoldCount is 0, lock is released, and
          //one waiting thread is notified.
         if(lockHoldCount==0)
             notify();

   }
  
   /**
   * Acquires the lock if it is not held by another thread and returns
   * true. And sets lock hold count to 1.
   * If current thread already holds lock then method
   * returns true. And increments lock hold count by 1.
   * If lock is held by another thread then method return false.
   */
   public synchronized boolean tryLock(){
          //Acquires the lock if it is not held by another thread and
          //returns true
          if(lockHoldCount==0){
                 lock();
                 return true;
          }
          //If lock is held by another thread then method return false.
          else
                 return false;
   }
}
/**
* Main class
*/
public class ReentrantLockCustomTest {
   public static void main(String[] args) {
      LockCustom LockCustom=new ReentrantLockCustom();
      MyRunnable myRunnable=new MyRunnable(LockCustom);
      new Thread(myRunnable,"Thread-1").start();
      new Thread(myRunnable,"Thread-2").start();
     
   }
}
class MyRunnable implements Runnable{
  
   LockCustom lockCustom;
   public MyRunnable(LockCustom LockCustom) {  
      this.lockCustom=LockCustom;
   }
  
   public void run(){
     
      System.out.println(Thread.currentThread().getName()
                   +" is Waiting to acquire LockCustom");
     
      lockCustom.lock();
      System.out.println(Thread.currentThread().getName()
                   +" has acquired LockCustom.");
     
      try {
             Thread.sleep(5000);
             System.out.println(Thread.currentThread().getName()
                          +" is sleeping.");
      } catch (InterruptedException e) {
             e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName()
                   +" has released LockCustom.");
     
     
      lockCustom.unlock();
   }
}
/*OUTPUT
Thread-1 is Waiting to acquire LockCustom
Thread-2 is Waiting to acquire LockCustom
Thread-1 has acquired LockCustom.
Thread-1 is sleeping.
Thread-1 has released LockCustom.
Thread-2 has acquired LockCustom.
Thread-2 is sleeping.
Thread-2 has released LockCustom.
*/



Let’s discuss output in detail, to get better understanding of Custom ReentrantLock usage in program in java >
Note : I have mentioned output in green text.


Thread-1 is Waiting to acquire lock
Thread-2 is Waiting to acquire lock
Thread-1 and Thread-2 are waiting to acquire lock.

Thread-1 has acquired lock.
Thread-1 has acquired lock by calling lock() method. (Now lock hold count=1)
Thread-2 has also called lock() method, but it will have to wait until lock hold count becomes 0. (lock hold count will become 0 when Thread-1 will call unlock() method)

Thread-1 is sleeping.
Thread-1 has released lock.
Thread-1 has released lock by calling unlock() method. (Now lock hold count=0)

Thread-2 has acquired lock.
Thread-2 has acquired lock by calling lock() method. (Now lock hold count=1)

Thread-2 is sleeping.
Thread-2 has released lock.
Thread-2 has released lock by calling unlock() method. (Now lock hold count=0)



Program/ Example to demonstrate usage of Custom ReentrantLock’s tryLock() method in java  >
public class ReentrantLockCustomTryLockTest {
   public static void main(String[] args) {
          LockCustom lockCustom=new ReentrantLockCustom();
          MyRunnable myRunnable=new MyRunnable(lockCustom);
          new Thread(myRunnable,"Thread-1").start();
          new Thread(myRunnable,"Thread-2").start();
         
   }
}
class MyRunnable implements Runnable{
  
   LockCustom lockCustom;
   public MyRunnable(LockCustom lockCustom) {  
          this.lockCustom=lockCustom;
   }
  
   public void run(){
         
          System.out.println(Thread.currentThread().getName()
                       +" is Waiting to acquire lock");
          try {
                 Thread.sleep(10);
          } catch (InterruptedException e) {
                 e.printStackTrace();
          }
         
          if(lockCustom.tryLock()){
                 System.out.println(Thread.currentThread().getName()
                              +" has acquired lock.");
                 try {
                       Thread.sleep(1000);
                 } catch (InterruptedException e) {
                       e.printStackTrace();
                 }
                
          }
          else{
                 System.out.println(Thread.currentThread().getName()
                              +" didn't got lock.");
                
          }
   }
}
/*OUTPUT
Thread-1 is Waiting to acquire lock
Thread-2 is Waiting to acquire lock
Thread-1 has acquired lock.
Thread-2 didn't got lock.
*/


Let’s discuss output in detail, to get better understanding of Custom ReentrantLock’s tryLock() method usage in program in java >
Note : I have mentioned output in green text.



Thread-1 is Waiting to acquire lock
Thread-2 is Waiting to acquire lock

Thread-1 has acquired lock.
thread-1 called lockCustom.tryLock(), lock was available. So, thread-1 acquired lock, method returned true and entered if block.

Thread-2 didn't got lock.
thread-1 called lockCustom.tryLock(), lock wasn’t available. So, method returned false and entered else block.






Application of using Custom ReentrantLock with program in java >

Custom Reentrantlocks can be used to solve Train-passenger problem when 2 passengers try to book train ticket, dat too when only 1 ticket is available.

Program to show that with Reentrantlocks no problems will happen when  2 passengers try to book train ticket, when only 1 ticket was available >
public class ReentrantLockCustomTest {
   public static void main(String[] args) {
          LockCustom lock=new ReentrantLockCustom();
          MyRunnable myRunnable=new MyRunnable(lock);
          new Thread(myRunnable,"Passenger1 Thread").start();
          new Thread(myRunnable,"Passenger2 Thread").start();
         
   }
}
class MyRunnable implements Runnable{
  
   int ticketsAvailable=1;
   LockCustom lockCustom;
   public MyRunnable(LockCustom lockCustom) {  
          this.lockCustom=lockCustom;
   }
  
   public void run(){
         
          System.out.println("Waiting to book ticket for : "+
                              Thread.currentThread().getName());
         
          lockCustom.lock();
          if(ticketsAvailable>0){
                 System.out.println("Booking ticket for : "+
                                     Thread.currentThread().getName());
                
                 //Let's say system takes some time in booking ticket
                 //(here we have taken 1 second time)
                 try{
                       Thread.sleep(1000);
                 }catch(Exception e){}
                  
                 ticketsAvailable--;
                 System.out.println("Ticket BOOKED for : "+
                                     Thread.currentThread().getName());
                 System.out.println("currently ticketsAvailable = "+ticketsAvailable);
          }
          else{
                 System.out.println("Ticket NOT BOOKED for : "+
                                     Thread.currentThread().getName());
          }
         
         
          lockCustom.unlock();
   }
}
/*OUTPUT
Waiting to book ticket for : Passenger1 Thread
Waiting to book ticket for : Passenger2 Thread
Booking ticket for : Passenger1 Thread
Ticket BOOKED for : Passenger1 Thread
currently ticketsAvailable = 0
Ticket NOT BOOKED for : Passenger2 Thread
*/


OUTPUT ANALYZATION of above program  in java>
Waiting to book ticket for : Passenger1 Thread
Waiting to book ticket for : Passenger2 Thread
first Passenger1 Thread and Passenger2 Thread waited to book tickets.

Booking ticket for : Passenger1 Thread
Than, Passenger1 Thread acquired lock [by calling lockCustom.lock() ], but Passenger2 Thread wasn’t able to acquire lock and was waiting for Passenger1 Thread to release lock.

Ticket BOOKED for : Passenger1 Thread
Passenger1 Thread was successfully able to book ticket and reduce the available ticket count to 0. Than it released object lock  [by calling lockCustom.unlock() ]
currently ticketsAvailable = 0

Ticket NOT BOOKED for : Passenger2 Thread
Than, Passenger1 Thread acquired lock [by calling lockCustom.lock() ], but available ticket count at that time was 0 so it wasn’t able to book ticket.



What will happen if thread that holds lock again calls lock() method?
Initially lock hold count = 0. When thread calls lock() method lock hold count is set to one (Now, lock hold count =1). If same thread again calls lock() method lock hold count is incremented by one (Now, lock hold count =2).

Now some other thread will be able to acquire lock only when lock hold count is 0. Thread will have to wait until lock hold count becomes 0.

When same thread calls unlock() method lock hold count is decremented by one (Now, lock hold count =1) and thread won’t release lock. If same thread again calls unlock() method lock hold count is decremented by one (Now, lock hold count =0), thread will release lock and some other thread can acquire lock.



Program/ Example to show will happen if thread that holds lock again calls lock() method in java >
public class ReentrantLockCustomTest {
   public static void main(String[] args) {
          ReentrantLockCustom lock=new ReentrantLockCustom();
      MyRunnable myRunnable=new MyRunnable(lock);
      new Thread(myRunnable,"Thread-1").start();
      new Thread(myRunnable,"Thread-2").start();
     
   }
}
class MyRunnable implements Runnable{
  
   ReentrantLockCustom lockCustom;
   public MyRunnable(ReentrantLockCustom lockCustom) {
      this.lockCustom=lockCustom;
   }
  
   public void run(){
     
                 System.out.println(Thread.currentThread().getName()
             +" is Waiting to acquire lock");
     
      lockCustom.lock();
      System.out.println();
      System.out.println(Thread.currentThread().getName()
                   +" has called lock(), lockHoldCount=1 ");
     
    
      lockCustom.lock();        
      System.out.println(Thread.currentThread().getName()
                   +" has called lock(), lockHoldCount=2 ");
     
      System.out.println(Thread.currentThread().getName()
                +" is about to call unlock(), lockHoldCount will become 1 ");
      lockCustom.unlock();   
     
     
      System.out.println(Thread.currentThread().getName()
                +" is about to call unlock(), lockHoldCount will become 0 ");
      lockCustom.unlock();
     
   }
}
/*OUTPUT
Thread-1 is Waiting to acquire lock
Thread-1 has called lock(), lockHoldCount=1
Thread-1 has called lock(), lockHoldCount=2
Thread-1 is about to call unlock(), lockHoldCount will become 1
Thread-1 is about to call unlock(), lockHoldCount will become 0
Thread-2 is Waiting to acquire lock
Thread-2 has called lock(), lockHoldCount=1
Thread-2 has called lock(), lockHoldCount=2
Thread-2 is about to call unlock(), lockHoldCount will become 1
Thread-2 is about to call unlock(), lockHoldCount will become 0
*/


Summary >

In previous thread concurrency tutorial we learned what is Locks and ReEntrantLocks in java and in this thread concurrency tutorial we learned what is Custom Lock in java, Custom Lock interface methods and  constructor in java, how to write Custom ReentrantLock’s code in java, Example to demonstrate usage of Custom ReentrantLock, Application of using Custom ReentrantLock with program in java.


Having any doubt? or you you liked the tutorial! Please comment in below section.
Please express your love by liking JavaMadeSoEasy.com (JMSE) on facebook, following on google+ or Twitter.





RELATED LINKS>

Executor and ExecutorService framework in java

Atomic operations in java

Semaphore in java

Phaser in java


No comments:

Post a Comment