Tuesday, February 22, 2011

Semaphores

What is Semaphore?

Semaphore is the new class introduced as a part of concurrency package in jdk 1.5 .It maintains a set of permits which gets acquired by thread before using some functionality.

It is a technique to protect your critical resource from being used by more than 'N' threads simultaneously.Semaphore maintains number of available permits.Whenever a thread wants to use some shared resource,maintained by semaphore.It asks semaphore for the permit.If permit is available thread can use the shared resource,otherwise it will wait till some other thread releases the permit or come out without using the shared resource.

Use cases where it can be used.

Semaphore with number of virtual permits more than 1 can be used as shared critical resource pools like database connection pool,license pool,worker thread pool and others.

Semaphore with number of virtual permits as 1 can be used as a lock.[Though I feel its waste of semaphore as we can use synchronized method/block and other techniques].You use it if you have permit to use it.

Mutex is often referred as Semaphore with number of virtual permits as 1,also called as Binary Semaphore.However there are marked differences between them.Semaphore does not track which thread has taken the permit.Semaphore does not track ownership of permits.However mutex keeps track of it.In case of Semaphore any thread can release the permit.But mutex can release only what it owns.

Important methods of semaphore

Following are important methods of Semaphore.These are:-
  • acquire()- When thread invokes acquire() on semaphore.If a token is available,it acquires the token.Other wise it goes into dormant state till the time it gets the token or some other thread has interrupted it.

  • acquire(int permits) -Its similar to acquire() except we can specify number of tokens to be required.Usually used when we require more than one token.

  • release()-When this method is invoked.It releases the permit and returns it back to Semaphore. Excerpt from Java API
    "There is no requirement that a thread that releases a permit must have acquired that permit by calling
    acquire. Correct usage of a semaphore is established by programming convention in the application."

  • release(int permits)-Similar to release() except that we are specifying number of tokens to be released.

  • tryAcquire()-acquire() method is kind of a blocking call.Calling thread will wait till it aquires the permit or some other thread has interrupted it.In case of tryAcquire() thread does not wait.It checks whether any token is available,if its available it picks the token and return with the value as true.Otherwise it come out with value as false.

  • tryAcquire(long timeUnits,TimeUnit unit)-Similar to tryAcquire() except that it wait for time period mentioned in method parameters before coming out.

Code snippet and license use case

UseCase-Custom product is configured for '2' concurrent users.What will happen if at a particular time more than '2' concurrent users try to use the product.For such conditions semaphore is plugged in the product and on each utility method ,thread requires a token.If token is not there,an exception is thrown stating "Please try the product after sometime".


CustomProduct.java having semaphore implementation for using the product
package com.kunaal.semaphore.product;

import java.util.concurrent.Semaphore;

/**
 * Custom fund transfer product.
 * Product is designed in such a way that number of concurrent user license
 * information is captured during object creation.
 * 
 * Semaphore implementation is plugged at all utility methods 
 * so that if we have more number of concurrent users than 
 * that provided at the object creation.
 * 
 * Other users will wait........
 * 
 * @author Kunaal A Trehan
 */
public class CustomProduct {

 /**
  * Semaphore object acting as a gatekeeper preventing users for using 
  * this product if no of users is more than the allowed 
  * concurrent users 
  */
 private final Semaphore semaphore; 
 
 /**
  * Variable for capturing number of concurrent users
  */
 private int concurrentUserNum;
 
 /**
  * Constructor
  * @param noOfConcurrentUsers
  */
 public CustomProduct(int noOfConcurrentUsers){
  semaphore=new Semaphore(noOfConcurrentUsers, true);
  concurrentUserNum=noOfConcurrentUsers;
 }
 
 /**
  * Method using semaphore preventing users more than concurrent users
  * configured to use this method.
  * 
  * @param threadName
  * @throws Exception
  */
 public void useProduct(String threadName) throws Exception{
  boolean acquireVal = semaphore.tryAcquire();
  String newLine = System.getProperty("line.separator");

  
  if(acquireVal){
   System.out.println("Thread with name-"+ threadName + " is using the product");
   Thread.sleep(2*1000);
   semaphore.release();
  }else{
   throw new Exception("[" +threadName + " can't use this product right now." + newLine+
     concurrentUserNum +" users can use this product concurrently" + newLine+ 
     " Please try after some time ]");
  }
 }
}


Runnable implementation invoking useProduct() method CustomProduct
package com.kunaal.semaphore.runnable;

import com.kunaal.semaphore.product.CustomProduct;


/**
 * Custom runnable invoking methods on custom product.
 * 
 * @author Kunaal A Trehan
 */
public class RunImpl implements Runnable {
 
 /**
  * Variable for custom product
  */
 private CustomProduct customProd;

 /**
  * Constructor
  * @param customProd
  */
 public RunImpl(CustomProduct customProd){
  this.customProd=customProd;
 }
 
 /**
  * Overridden run method
  */
 @Override
 public void run() {
  try{
   String name = Thread.currentThread().getName();
   customProd.useProduct(name);
  }catch(Exception e){
   System.out.println("Exception message is-" +e.getMessage());
  }
 }

 /**
  * @return the customProd
  */
 public CustomProduct getCustomProd() {
  return customProd;
 }

 /**
  * @param customProd the customProd to set
  */
 public void setCustomProd(CustomProduct customProd) {
  this.customProd = customProd;
 }
 
}


Main class showing what will happen when more than 2 threads try to use the product
package com.kunaal.semaphore;

import com.kunaal.semaphore.product.CustomProduct;
import com.kunaal.semaphore.runnable.RunImpl;

/**
 * This example states the use of semaphore.
 * Here thread tries to acquire token from semaphore.If token is available
 * thread acquires it and uses the product.
 * Otherwise it throws the exception that token is not available
 * 
 * In the main we create 4 threads.After starting 3 threads.
 * Current thread is put to sleep for 4 sec so that during that 
 * time one of threads using the token releases the token 
 * and thread no04 can use the product.
 * 
 * @author Kunaal A Trehan
 *
 */
public class NonWaitingExample {

 /**
  * @param args
  * @throws InterruptedException 
  */
 public static void main(String[] args) throws InterruptedException {
  CustomProduct product=new CustomProduct(2);
  RunImpl runImpl=new RunImpl(product);
  
  Thread t1=new Thread(runImpl,"User-1");
  Thread t2=new Thread(runImpl,"User-2");
  Thread t3=new Thread(runImpl,"User-3");
  Thread t4=new Thread(runImpl,"User-4");
  
  t1.start();
  t2.start();
  t3.start();
  System.out.println("Time before main thread sleeps-"+System.currentTimeMillis());
  Thread.currentThread().sleep(4*1000);
  System.out.println("Time after main thread finishes sleep-"+System.currentTimeMillis());
  t4.start();
  
 } 
}


Output of the main programm
Thread with name-User-1 is using the product
Thread with name-User-2 is using the product
Time before main thread sleeps-1298361121828
Exception message is-[User-3 can't use this product right now.
2 users can use this product concurrently
 Please try after some time ]
Time after main thread finishes sleep-1298361125828
Thread with name-User-4 is using the product

1 comment:

  1. I have read your blog its very attractive and impressive. I like it your blog.

    Java Online Training Java EE Online Training Java EE Online Training Java 8 online training Java 8 online training

    Java Online Training from India Java Online Training from India Core Java Training Online Core Java Training Online Java Training InstitutesJava Training Institutes

    ReplyDelete