ThreadLocal原理及用法

版权声明:本文为博主原创文章,转载请说明出处 https://blog.csdn.net/u010002184/article/details/82145185
import java.util.ArrayList;
import java.util.HashMap;

public class Main {

    //ThreadLocal<HashMap> totalMap = new ThreadLocal<HashMap>();//return null; 会造成NullPointerException
    ThreadLocal<HashMap> totalMap = new ThreadLocal<HashMap>() {//每个线程下的ThreadLocalMap里有一个Entry的key是totalMap
        @Override
        protected HashMap initialValue() {
            //return super.initialValue();//  return null; 会造成NullPointerException
            System.out.println(Thread.currentThread().getName() + " totalMap initialValue...");
            return new HashMap();
        }
    };


    ThreadLocal<ArrayList> totalList = new ThreadLocal<ArrayList>() {//每个线程下的ThreadLocalMap里有一个Entry的key是totalList
        @Override
        protected ArrayList<Integer> initialValue() {
            System.out.println(Thread.currentThread().getName() + " totalList initialValue...");
            return new ArrayList<Integer>();
        }
    };

    public void test() {
        Thread[] runs = new Thread[3];
        for (int id = 0; id < 2; id++) {
            runs[id] = new Thread(new T1(id));//id参数是每个线程的独有标识
            runs[id].start();
        }
    }

    class T1 implements Runnable {
        int id;

        public T1(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            //
            HashMap map = totalMap.get();//这个map是该线程对应的ThreadLocalMap里的一个Entry里的value,totalMap是该Entry的key
            System.out.println("totalMap:" + totalMap);
            for (int j = 0; j < 5; j++) {
                map.put(j, j + id * 100);//每个线程有自己的map,虽然key相同,但是并没有把value覆盖
            }
            System.out.println("map.hashCode:" + map.hashCode());
            System.out.println(Thread.currentThread().getName() + ",map:" + map);


            ArrayList<Integer> list = totalList.get();////这个map是该线程对应的ThreadLocalMap里的一个Entry里的value,totalList是该Entry的key
            System.out.println("totalList:" + totalList);
            for (int j = 0; j < 5; j++) {
                list.add(j + id * 100);
            }
            System.out.println("list.hashCode:" + list.hashCode());
            System.out.println(Thread.currentThread().getName() + ",list:" + list);
        }
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.test();
    }

}

输出:

Thread-0 totalMap initialValue...
totalMap:Main$1@77724958
Thread-1 totalMap initialValue...
map.hashCode:0
Thread-0,map:{0=0, 1=1, 2=2, 3=3, 4=4}
totalMap:Main$1@77724958
map.hashCode:508
Thread-1,map:{0=100, 1=101, 2=102, 3=103, 4=104}
Thread-1 totalList initialValue...
totalList:Main$2@7fe8489f
Thread-0 totalList initialValue...
list.hashCode:124091461
totalList:Main$2@7fe8489f
Thread-1,list:[100, 101, 102, 103, 104]
list.hashCode:28660961
Thread-0,list:[0, 1, 2, 3, 4]

总结:

1 每个线程Thread对应一个ThreadLocalMap
2 ThreadLocalMap是由Entry数组组成,元素是键值对,
3 该ThreadLocal<?>变量名是共用的,每个线程的ThreadLocalMap的Entry的key就是该变量名,value就是各自的内容
4 有几个共用的ThreadLocal<?>变量,则每个线程的ThreadLocalMap就有几个Entry,Entry数组初始容量是16,后续可以进行扩容

源码:

    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }


    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }


    /**
     * Returns the current thread's "initial value" for this
     * thread-local variable.  This method will be invoked the first
     * time a thread accesses the variable with the {@link #get}
     * method, unless the thread previously invoked the {@link #set}
     * method, in which case the {@code initialValue} method will not
     * be invoked for the thread.  Normally, this method is invoked at
     * most once per thread, but it may be invoked again in case of
     * subsequent invocations of {@link #remove} followed by {@link #get}.
     *
     * <p>This implementation simply returns {@code null}; if the
     * programmer desires thread-local variables to have an initial
     * value other than {@code null}, {@code ThreadLocal} must be
     * subclassed, and this method overridden.  Typically, an
     * anonymous inner class will be used.
     *
     * @return the initial value for this thread-local
     */
    protected T initialValue() {
        return null;
    }
initialValue方法的注释:如果编程者期望初始化一个非空的变量,必须要重写这个方法,典型的可以使用匿名内部类。如果不重写该方法会报错。

参考:

https://www.jianshu.com/p/c64f06f0823b  Java ThreadLocal 原理分析
http://www.cnblogs.com/digdeep/p/4510875.html  ThreadLocal 源码剖析

猜你喜欢

转载自blog.csdn.net/u010002184/article/details/82145185