Hi,
After my post concerning Multi tasks, Multi threading, Synchronization, Semaphore, Mutex, Barrier, I will try to explain the class ThreadLocal in this first post of June month (2012). What is a ThreadLocal? When should I use a ThreadLocal variable? What is the differences between Thread and ThreadLocal?
Since long time, threads are used in the application’s development, however as its name doesn’t suggests, ThreadLocal is not a “local thread” but a class providing thread-local variables without implementations of semaphore or mutex. The official definition is that “the ThreadLocal variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread“. So Thread and ThreadLocal are not the same thing.
Introduction
For example, here, a classe defining a static counter accessed by several threads:
public class MyValueData { // Counter n°1 public static Integer counter = new Integer(0); public MyValueData(){ } }
If, an unique instance of ‘MyValueData’ class is created and accessed by several threads like:
MyValueData myValueData = new MyValueData(); Thread T1 = new Thread(myValueData); Thread T2 = new Thread(myValueData);
… then the ‘counter’ attribut of ‘myValueData’ instance will be shared by the 2 threads.
But, it is possible to create distinct instance of ‘MyValueData’ class used by these 2 threads like:
Thread T1 = new Thread(new MyValueData()); Thread T2 = new Thread(new MyValueData());
… it’s right. However, if it is necessary to share some attributs among threads, and don’t share others (attributs), the use of ‘ThreadLocal’ is helpfull.
Advanced example
Here, a classe defining 2 static counters accessed by several threads:
public class MyValueData { // Counter n°1 private Integer counter = new Integer(0); // Counter n°2 private ThreadLocal<Integer> counterThreadLocal = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 0; } }; public MyValueData(){ } public synchronized Integer getCounter() { return counter; } public synchronized void incrementCounter() { this.counter++; } public Integer getCounterThreadLocal() { return counterThreadLocal.get(); } public void incrementCounterThreadLocal() { this.counterThreadLocal.set(this.counterThreadLocal.get()+1); } }
Then, we define a Runnable which:
1- starts and sleeps during a random time (defined at the construction time),
2- increments the 2 counters,
3- repeats the steps 1 and 2 until the counter n°1 is equal or greater than 10;
public class MyTask implements Runnable { private int sleepTime; // random sleep time for thread private String threadName; // name of thread private MyValueData myValueData; public MyTask(String name, MyValueData myValueData) { // set name of thread this.threadName = name; // random sleep time between 0 and 5 seconds this.sleepTime = new Random().nextInt( 5000 ); this.myValueData = myValueData; } public void run() { try{ while(this.myValueData.getCounter()<10){ // put thread to sleep for sleepTime amount of time System.out.printf("%s starting and going to sleep for %d milliseconds: MyValueData.counter=%d, MyValueData.counterThreadLocal=%d \n", this.threadName, this.sleepTime, this.myValueData.getCounter(), this.myValueData.getCounterThreadLocal()); // put thread to sleep Thread.sleep( this.sleepTime ); // Increment this.myValueData.incrementCounter(); this.myValueData.incrementCounterThreadLocal(); } } catch ( InterruptedException exception ) { exception.printStackTrace(); } // print thread name System.out.printf( "%s done sleeping\n", this.threadName ); } }
At last, the main method which will:
– create a instance of ‘MyValueData’ class containing the 2 counters,
– create 3 threads named “threadname_1”, “threadname_2” and “threadname_3” with the above instance of ‘MyValueData’,
– execute these 3 threads due to an ExecutorService;
public static void main(String[] args) { // create and name each runnable MyValueData myValueData = new MyValueData(); MyTask th1 = new MyTask("threadname_1", myValueData); MyTask th2 = new MyTask("threadname_2", myValueData); MyTask th3 = new MyTask("threadname_3", myValueData); // create ExecutorService to manage threads OR empty (better) ExecutorService es = Executors.newFixedThreadPool(3); // start threads and place in runnable state es.execute(th1); es.execute(th2); es.execute(th3); // shutdown worker threads es.shutdown(); }
…so the ouputs in console would be like the following traces. In these outputs, we could see that the counter n°1 (MyValueData.counter) is shared by all threads, whereas the counter n°2 (MyValueData.counterThreadLocal) has an unique value for each created thread. At the end, the value of this counter n°2 is:
– threadname_1: MyValueData.counterThreadLocal=2,
– threadname_2: MyValueData.counterThreadLocal=5,
– threadname_3: MyValueData.counterThreadLocal=2;
threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=0, MyValueData.counterThreadLocal=0 threadname_3 starting and going to sleep for 1323 milliseconds: MyValueData.counter=0, MyValueData.counterThreadLocal=0 threadname_1 starting and going to sleep for 1113 milliseconds: MyValueData.counter=0, MyValueData.counterThreadLocal=0 threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=1, MyValueData.counterThreadLocal=1 threadname_1 starting and going to sleep for 1113 milliseconds: MyValueData.counter=2, MyValueData.counterThreadLocal=1 threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=3, MyValueData.counterThreadLocal=2 threadname_3 starting and going to sleep for 1323 milliseconds: MyValueData.counter=4, MyValueData.counterThreadLocal=1 threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=5, MyValueData.counterThreadLocal=3 threadname_1 starting and going to sleep for 1113 milliseconds: MyValueData.counter=6, MyValueData.counterThreadLocal=2 threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=7, MyValueData.counterThreadLocal=4 threadname_3 starting and going to sleep for 1323 milliseconds: MyValueData.counter=8, MyValueData.counterThreadLocal=2 threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=9, MyValueData.counterThreadLocal=5 threadname_1 done sleeping threadname_2 done sleeping threadname_3 done sleeping
Conclusion
In this post, we could see a main use case of the ‘ThreadLocal’ class which is to able to assign a unique data to each thread.
Best regards,