Java Thread Local

What is Thread Local? 

Thread Local can be considered as a scope of access, like a request scope or session scope. It’s a thread scope. You can set any object in Thread Local and this object will be global and local to the specific thread which is accessing this object. Global and local!!? Let me explain:

  • Values stored in Thread Local are global to the thread, meaning that they can be accessed from anywhere inside that thread. If a thread calls methods from several classes, then all the methods can see the Thread Local variable set by other methods (because they are executing in same thread). The value need not be passed explicitly. It’s like how you use global variables.
  • Values stored in Thread Local are local to the thread, meaning that each thread will have it’s own Thread Local variable. One thread cannot access/modify other thread’s Thread Local variables.

How it works

http://theyjustdidit.com/what-is-java-threadlocal-and-what-is-its-use/

Let us assume, I have a class named SharedClass (let us assume it is a Singleton class). The singleton object of this class – say named as ’shared’ is accessed and manipulated by 10 threads.

Now, knowing the above situation, I have a particular requirement where, I want to specify a variable in the class, which cannot be shared by the threads. That means, every thread have its own value for the variable that cannot be seen or modified by another thread.

Implementation without ThreadLocal

 

If there is no ThreadLocal, one way to implement this is by using a Map in Java. In such a map, the key will be the thread id and the value will be the variable for that particular thread. So every thread, if they want to see their value or modify it, has to do a get() from this map using its thread id.

Following may the implementation of the SharedClass (without ThreadLocal)

public class SharedClass {

Map<Long, Integer> threadLocalVariableMap = new HashMap<Long, Integer>();

/**

* Get specific variable for the thread that is accessing on the singleton

* @return thread specific variable.

*/

public synchronized Integer getThreadSpecificVariable(){

Long threadId = Thread.currentThread().getId();

Integer threadLocalVariable = threadLocalVariableMap.get(threadId);

if (threadLocalVariable == null){

//Have an intitial value

threadLocalVariable = new Integer(0);

threadLocalVariableMap.put(threadId, threadLocalVariable);

}

return threadLocalVariable;

}

/**

* Set the modified thread specific variable

* @param newVariable – the new value for the thread specific variable

*/

public synchronized void setThreadSpecificVariable(Integer newVariable){

Long threadId = Thread.currentThread().getId();

threadLocalVariableMap.put(threadId, newVariable);

}

}

Implementation with ThreadLocal

The entire implementation with the Map can be replaced by using an instance of ThreadLocal class than a HashMap. Instead of using map.get() using the threadId as key, the Java will internally manage everything (probably that is the way ThreadLocal is actually implemented – using HashMap and threadId as key) .

So now, instead of a Map storing the values for each thread, the ThreadLocal will manage it (even without the developer passing the thread id). So to get the local variable for the thread, the thread just has to call get() method and to set a variable for the thread, it will need to call the set() method on the ThreadLocal variable. Additionally, there is no need for initializing explicitly by checking for a null value. The method initialValue() of the ThreadLocal can be used to initialize a value for the thread. This method will be used when the first get() is done and if there is no initialization already happened.

You can also see that the methods are not synchronized in this implementation .

public class SharedClass {

 ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
 protected Integer initialValue(){
 return new Integer(0);
 }
 };

 /**
 * Get specific variable for the thread that is accessing on the singleton
 * @return thread specific variable.
 */
 public Integer getThreadSpecificVariable(){

 Integer threadLocalVariable = threadLocal.get();
 //Initializing value is done by the initialValue() method of ThreadLocal
 //that method will be called if the get() returns null

 return threadLocalVariable;
 }

 /**
 * Set the modified thread specific variable
 * @param newVariable - the new value for the thread specific variable
 */
 public void setThreadSpecificVariable(Integer newVariable){
 threadLocal.set(newVariable);
 }

}

Example :

package test.thrdlocal;

public class ThreadLocalMain {

public static void main(String[] args) {

Runnable runnable = new MyThreadLocalRunner();

Thread thrd = new Thread(runnable);

System.out.println(“Inside ThreadLocalMain  :: START……….”);

//set the value in threadLocal

MyThreadLocal.set(1);

//set the value in Non threadLocal

//MyNonThreadLocal.set(1);

BusinessService.print();

System.out.println(“Inside ThreadLocalMain  :: BEFORE MyThreadLocalRunner……….”);

thrd.start();

try {

Thread.sleep(2000);

catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“Inside ThreadLocalMain  :: BETWEEN MyThreadLocalRunner……….”);

try {

thrd.join();

catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“Inside ThreadLocalMain  :: AFTER MyThreadLocalRunner……….”);

BusinessService.print();

System.out.println(“Inside ThreadLocalMain  :: STOP……….”);

}

}

class MyThreadLocalRunner implements Runnable {

@Override

public void run() {

System.out.println(“Inside MyThreadLocalRunner  :: START……….”);

//set the value in threadLocal

MyThreadLocal.set(2);

//set the value in Non threadLocal

//MyNonThreadLocal.set(2);

try {

Thread.sleep(3000);

catch (InterruptedException e) {

e.printStackTrace();

}

BusinessService.print();

System.out.println(“Inside MyThreadLocalRunner  :: STOP……….”);

}

}

class MyThreadLocal {

public static ThreadLocal<Integer> userThreadLocal = new ThreadLocal<Integer>();

public static void set(Integer i) {

userThreadLocal.set(i);

}

public static void unset() {

userThreadLocal.remove();

}

public static Integer get() {

return userThreadLocal.get();

}

}

class MyNonThreadLocal {

public static  Integer userNonThreadLocal;

public static void set(Integer i) {

userNonThreadLocal = i;

}

public static void unset() {

userNonThreadLocal = null;

}

public static Integer get() {

return userNonThreadLocal;

}

}

class BusinessService {

public static void print() {

//Print the value in threadLocal

System.out.println(MyThreadLocal.get());

//Print the value in Non threadLocal

//System.out.println(MyNonThreadLocal.get());

}

}

http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s