Friday, February 7, 2014

Thread-local variable in Java

Instances of a class maintain their own state through non-static data attributes. So, if you create 100 instances of Student class, they all have their own copy of name, age etc. Like this, life continues for objects and it's all cool!

Along with objects, Java has another level of abstraction (more lower level than objects); threads. The obvious question is, how are you going to manage state among multiple threads?  
In below code snippet, local variable, state can't keep value specific to each thread.

 sampleMethod(){  
  String state = "default";  
  Thread t1 = new Thread(){  };  //thread 1  
  Thread t2 = new Thread(){  };  //thread 2
 }  

Literally,  thread-local means, something which is local to a thread. One way to keep a variable local to a thread is;  inherit Thread class and add state.  And create unique objects for each thread. This solution can only work in trivial situations; and in some cases it might not be even feasible. Definitely there is a need for a cleaner approach.

 public class MyThread extends Thread{  
     String state;  
     public void run() { ... }   
 }   

java.lang.ThreadLocal<T> class

Java provides a specific class (since version 1.2) named as ThreadLocal, which allows you to associate a per-thread value with a value-holding object. This object provides get and set accessor methods that maintain a separate copy of the value for each thread that uses it. Below is a simplest example to illustrate the point. 

1:  public class ThreadLocalDemo {  
2:       private static ThreadLocal<String> tl = new ThreadLocal<String>();  
3:       public static void main(String[] args) {  
4:            tl.set("Main Thread");  
5:            Runnable r = new Runnable(){  
6:                 public void run(){  
7:                      tl.set("Sub Thread");  
8:                      System.out.println("Thread Local in Sub Thread :"+ tl.get());  
9:                      tl.remove();  
10:                 }                 
11:            };  
12:            System.out.println("Thread Local in Main :"+ tl.get());  
13:            Thread t = new Thread(r);  
14:            t.start();  
15:            tl.remove();  
16:       }  
17:  }  

Output:

Thread Local in Main : Main Thread

Thread Local in Sub Thread :Sub Thread


Note that, in the above class there are two threads (JVM runs this program in a separate thread and calls the main method and then there is a second thread (as t) created by the main method). The output clearly confirms that values stored in ThreadLocal object by two threads are preserved without any external synchronization. So, irrespective of the number of threads, ThreadLocal will create and maintain one unique storage for each thread. Method, get is used to return most recent value passed to set method from the currently executing thread. Conceptually, ThreadLocal can be visualized as a Map which stores value for each thread. (i.e. ThreadLocal<T>  equivalent to  Map<Thread, T>).

Let's go through a non-trivial example. Below is a ThreadLocalHolder class, which creates five threads for displaying thread-local behavior. Inner class, MyThreadLocal manages all methods of ThreadLocal class. Method, initialValue() is used to set an initial value.

1:  import java.util.Random;  
2:  public class ThreadLocalHolder implements Runnable {  
3:       private static Random rand = new Random(21);  
4:       class MyThreadLocal {  
5:            private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {  
6:                 protected Integer initialValue() {  
7:                      return rand.nextInt(100);  
8:                 }  
9:            };  
10:            public Integer getValue() {  
11:                 return tl.get();  
12:            }  
13:            public void setValue(Integer v) {  
14:                 tl.set(v);  
15:            }  
16:            public void remove() {  
17:                 tl.remove();  
18:            }  
19:       }  
20:       @Override  
21:       public void run() {  
22:            MyThreadLocal tlc = new MyThreadLocal();  
23:            tlc.setValue(rand.nextInt(1000));  
24:            System.out.println(" Val for thread : " + tlc.getValue());  
25:            // task logic  
26:            tlc.remove();  
27:       }  
28:       public static void main(String[] args) throws InterruptedException {  
29:            ThreadLocalHolder tlh = new ThreadLocalHolder();  
30:            for (int i = 0; i < 5; i++) {  
31:                 Thread t = new Thread(tlh);  
32:                 t.start();  
33:            }  
34:       }  
35:  }  

Output:

 Val for thread :  144
 Val for thread :  724
 Val for thread :  320
 Val for thread :  627
 Val for thread :  478

Final Note

You should be very careful in using ThreadLocal class. The value stored in this object stays as long as the thread is active.
So it could create an issue if your application is running in an Application server thread? In such case, the object stored in ThreadLocal will never get reclaimed as long as your application is up and running. 

--
Time to call it a post..do drop your feedback/comments. 

No comments:

Post a Comment