Search code examples
javathread-local

java.lang.ThreadLocal - How each Thread has its own, independently initialized copy of the variable?


The javadoc about the class java.lang.ThreadLocal is making me confused. They are saying that each thread that access a thread-local variable has its own, independently initialized copy of the variable. Here is an example (not a true life example) who proves that variable held in a thread-local variable could be shared by many threads:

package com.mohamad.test.threadlocal;

import java.util.List;

public class ThreadLocalExample {

    private static final ThreadLocal<List<Integer>> myThreadLocal = new ThreadLocal<List<Integer>>();

    public static List<Integer> get() {
        return (myThreadLocal.get());
    }

    public static void set(List<Integer> value) {
        myThreadLocal.set(value);
    }
}


package com.mohamad.test.threadlocal;

import java.util.ArrayList;
import java.util.List;


public class TestThreadLocal implements Runnable {

    private static List<Integer> MY_TEST_LIST = new ArrayList<Integer>(){
        /** The serialVersionUID */
        private static final long serialVersionUID = -2419885728976816054L;
        {add(1);}
    };


    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    public void run() {
        ThreadLocalExample.set(MY_TEST_LIST);
        List<Integer> integers = ThreadLocalExample.get();
        integers.remove(0);
        System.out.println(Thread.currentThread().getName() + " finished successfully, The list's size is: "  + ThreadLocalExample.get().size() + "\n");
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        TestThreadLocal thread1 = new TestThreadLocal();
        Thread t1 = new Thread(thread1);
        t1.start();
        TestThreadLocal thread2 = new TestThreadLocal();
        Thread t2 = new Thread(thread2);
        t2.start();
    }
}

If we run this exemple, a java.lang.IndexOutOfBoundsException will be thrown because of the MY_TEST_LIST that is shared by thread1 and thread2. (And as we saw, when thread1 and thread2 called the set(MY_TEST_LIST) method of ThreadLocalExample, that called the set method of the ThreadLocal variable, it didn't create an independent local copy of the MY_TEST_LIST)

If somebody has already asked this question, please give the link to the answer because i did't find anything interesting while making a research on google.

Regards,


Solution

  • Everything is fine. Variable hold in ThreadLocal is local to the thread. In your case it is a reference that is local, not the list itself. Each thread has its own copy of the reference, but all these references point to the same location. In other words: each thread can keep a reference to a different List but in your case they all point to the same one.

    If you want your example to work, each ThreadLocal should point to a different ArrayList (a copy):

    myThreadLocal.set(new ArrayList<Integer>(value));
    

    Having ThreadLocals all pointing to the same object doesn't make much sense as in this case you only need a single, globally available reference.