JavaBlog.fr / Java.lu DEVELOPMENT,Java Java: ThreadLocal, what is it?

Java: ThreadLocal, what is it?

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:

1public class MyValueData {
2 
3    // Counter n°1
4    public static Integer counter = new Integer(0);
5 
6    public MyValueData(){ }
7     
8}

If, an unique instance of ‘MyValueData’ class is created and accessed by several threads like:

1MyValueData myValueData = new MyValueData();
2Thread T1 = new Thread(myValueData);
3Thread 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:

1Thread T1 = new Thread(new MyValueData());
2Thread 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:

01public class MyValueData {
02    // Counter n°1
03    private Integer counter = new Integer(0);
04     
05    // Counter n°2
06    private ThreadLocal<Integer> counterThreadLocal = new ThreadLocal<Integer>(){
07        @Override protected Integer initialValue() { return 0; }
08    };
09 
10    public MyValueData(){ }
11 
12    public synchronized Integer getCounter() { return counter; }
13 
14    public synchronized void incrementCounter() { this.counter++; }
15 
16    public Integer getCounterThreadLocal() {
17        return counterThreadLocal.get();
18    }
19    public void incrementCounterThreadLocal() { this.counterThreadLocal.set(this.counterThreadLocal.get()+1); }
20 
21}

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;

01public class MyTask implements Runnable {
02 
03    private int sleepTime; // random sleep time for thread  
04    private String threadName; // name of thread  
05     
06    private MyValueData myValueData;
07     
08    public MyTask(String name, MyValueData myValueData) {
09        // set name of thread
10        this.threadName = name;
11        // random sleep time between 0 and 5 seconds
12        this.sleepTime = new Random().nextInt( 5000 );
13        this.myValueData = myValueData;
14    }
15 
16    public void run() {
17        try{
18            while(this.myValueData.getCounter()<10){
19                // put thread to sleep for sleepTime amount of time
20                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());
21 
22                // put thread to sleep
23                Thread.sleep( this.sleepTime );
24                 
25                // Increment
26                this.myValueData.incrementCounter();
27                this.myValueData.incrementCounterThreadLocal();
28            }
29        } catch ( InterruptedException exception )  { 
30            exception.printStackTrace();
31        }
32        // print thread name
33        System.out.printf( "%s done sleeping\n", this.threadName ); 
34    }
35         
36}

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;

01public static void main(String[] args) {
02     
03    // create and name each runnable
04    MyValueData myValueData = new MyValueData();
05    MyTask th1 = new MyTask("threadname_1", myValueData);
06    MyTask th2 = new MyTask("threadname_2", myValueData);
07    MyTask th3 = new MyTask("threadname_3", myValueData);
08 
09    // create ExecutorService to manage threads OR empty (better)
10    ExecutorService es = Executors.newFixedThreadPool(3);
11     
12    // start threads and place in runnable state
13    es.execute(th1);
14    es.execute(th2);
15    es.execute(th3);
16 
17    // shutdown worker threads 
18    es.shutdown();
19 
20}

…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;

01threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=0, MyValueData.counterThreadLocal=0
02threadname_3 starting and going to sleep for 1323 milliseconds: MyValueData.counter=0, MyValueData.counterThreadLocal=0
03threadname_1 starting and going to sleep for 1113 milliseconds: MyValueData.counter=0, MyValueData.counterThreadLocal=0
04threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=1, MyValueData.counterThreadLocal=1
05threadname_1 starting and going to sleep for 1113 milliseconds: MyValueData.counter=2, MyValueData.counterThreadLocal=1
06threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=3, MyValueData.counterThreadLocal=2
07threadname_3 starting and going to sleep for 1323 milliseconds: MyValueData.counter=4, MyValueData.counterThreadLocal=1
08threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=5, MyValueData.counterThreadLocal=3
09threadname_1 starting and going to sleep for 1113 milliseconds: MyValueData.counter=6, MyValueData.counterThreadLocal=2
10threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=7, MyValueData.counterThreadLocal=4
11threadname_3 starting and going to sleep for 1323 milliseconds: MyValueData.counter=8, MyValueData.counterThreadLocal=2
12threadname_2 starting and going to sleep for 592 milliseconds: MyValueData.counter=9, MyValueData.counterThreadLocal=5
13threadname_1 done sleeping
14threadname_2 done sleeping
15threadname_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,

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.

Related Post