Thursday, April 26, 2012

ThreadLocal in Java



Thread local class is to share information across multiple threads where each thread will have independent copy of the variable. We can use syncronization for the same but it is expensive. If there are frequent read operations , less number of modify operations and no interdependence among state variables across different threads,we can use thread local variables.



Thread local variables can be used when each thread wants to get default initialized copy of the variable and modify it as per their algorithm and use it across.It does not depend on the state variable in different threads.
Example:Lets take one use case in which we span multiple threads and create a thread local variable for the simple String as myFavPlace.Here depending upon the thread name we set myFavPlace in thread local variable which is then used by another class to print the current myFavPlace value.
Attached is the code snippet for reference



package threadLocal;
public class ThreadLocalExample{
 
  public static void main(String[] args) {
   Runnable runnable=new RunnableImpl();
   Thread thread1=new Thread(runnable,"USA");
   Thread thread2=new Thread(runnable,"UK");  
   Thread thread3= new Thread(runnable);
   Thread thread4= new Thread(runnable, "Europe");
  
   thread1.start();
   thread2.start();
   thread3.start();
   thread4.start();
  }
}


public class RunnableImpl implements Runnable {
  /**
   * Overridden run method implementation for Thread
   * Here depending upon the thread name we put String myFavPlace in
   * thread local variable which is then used  to print the
   * current place
   */
  @Override
  public void run() {
   String name = Thread.currentThread().getName();
  
   if(name !=null){
    if(name.equals("USA")){
       ThreadLocalDataHolder.setMyFavPlace(" Denver " );
    }else if(name.equals("UK")){
     ThreadLocalDataHolder.setMyFavPlace(" Gibraltor " );
    }else if(name.equals("Europe")) {
     ThreadLocalDataHolder.setMyFavPlace(" Belgium ");
    }
   }
  
   System.out.println("Thread Name -"+ Thread.currentThread() + " Current state is -"+ ThreadLocalDataHolder.getMyFavPlace());   
  
  }
 }


public class ThreadLocalDataHolder {

 private static ThreadLocal<String> myFavPlace=new ThreadLocal<String>(){
    public String initialValue() {
       System.out.println(" magic magic ");
           return new String();
       }  
   };
  
   public static void setMyFavPlace(String value){ 
    myFavPlace.set(value);
   }
  
   public static String getMyFavPlace(){
    return myFavPlace.get();
   }
}

output 
Thread Name -Thread[Thread-0,5,main] Current state is -
Thread Name -Thread[UK,5,main] Current state is - Gibraltor
Thread Name -Thread[Europe,5,main] Current state is - Belgium
Thread Name -Thread[USA,5,main] Current state is - Denver


you can also test with out locale in ThreadLocalDataHolder.java and see the output (without locale)

 public class ThreadLocalDataHolder { 

 private static String myFavPlace = " empty ";

 public static void setMyFavPlace(String value)
 {
  myFavPlace = value;
 }
 
 public static String getMyFavPlace()
 {
  return myFavPlace;
 }
}
output without Locale
Thread Name -Thread[UK,5,main] Current state is - Gibraltor
Thread Name -Thread[Europe,5,main] Current state is - Gibraltor
Thread Name -Thread[USA,5,main] Current state is - Gibraltor
Thread Name -Thread[Thread-0,5,main] Current state is - Gibraltor



 Where all thread locals are used?Its widely used in lots of frameworks like Spring ,Hibernate and others for passing particular thread specific information like transaction attributes,connection details,authorization information and others.

Is Thread Local safe to use or does it have some issues?
If thread local variables are not handled properly,it may lead to Class loader memory leak issue.Normally we get errors like this OutOfMemory: PermGen error...............................
Reason being if we don't clear the thread local variables after use and if thread local variables references some object.It will still be there and won't be garbage collected even though thread has finished the execution.Gradually with multiple installations/un-installations or multiple threads being spawned this memory issue will cause application to crash .So we should take proper care of removing the referencing to objects in thread local variables after use.