ThreadLocal原理详解

注:jdk 1.8
先讲的是具体实现,后面是总结,可以根据个人喜好调整顺序

1、  在线程内部有一个ThreadLocalMap属性;

/* ThreadLocal values pertaining to this thread. This map is maintained

* by the ThreadLocal class. */

ThreadLocal.ThreadLocalMap threadLocals = null;

 

2、  ThreadLocal内主要的属性成员和方法成员:

主要的方法成员:

public T get();//返回当前线程内ThreadLocal变量的副本,可能需要先初始化;

public void set(T value);//为当前线程内ThreadLocal变量的副本赋值,可能需要先初始化;

public void remove();//从当前线程的ThreadLocalMap属性的Entry数组中移除该ThreadLocal对应的Entry

ThreadLocalMap getMap(Thread t);//返回线程tThreadLocalMap属性;

private T setInitialValue();//初始化;

void createMap(Thread t, T firstValue);//为线程tThreadLocalMap进行初始化。

 

主要的数据成员:

private final int threadLocalHashCode;//用来保存当前ThreadLocal的哈希码;

private static AtomicInteger nextHashCode;//用来计算ThreadLocal的哈希码,确保每个ThreadLocal的实例的哈希码均不相同;

private static final int HASH_INCREMENT;//通过原子性的给nextHashCode增加该值确保ThreadLocal哈希值的唯一性。

 

主要内部类ThreadLocalMap的相关信息(很像是HashMap的简化版本):

主要的数据成员:

private static final int INITIAL_CAPACITY;//初始容量,必须是2的幂;

private Entry[] table;//Entry数组,需要时进行扩容,长度必须是2的幂;

private int size;//tableEntry的数量;

private int threshold;//当容量达到threshold3/4时需要进行扩容,值为table长度的2/3

 

主要的方法成员:

private void setThreshold(int len);//用来设置shreshold的值;

private static int nextIndex(int i, int len);//用来对i进行循环加1,当达到len时,重置为0

private static int prevIndex(int I, int len);//用来对i进行循环减1,当达到0时,重置为len-1

private Entry getEntry(ThreadLocal<?> key);//table表中查找key对应的Entry,通过key的哈希码&(table.length-1)得到table中的索引i,如果table[i]==key,返回Entry,否则继续寻找下一个,找不到返回null

private void set(ThreadLocal<?> key, Object value);//更新或者插入(key,value)

private void remove(ThreadLocal<?> key);//移除key对应的Entry

private void rehash();//size的值达到threshold3/4时,进行扩容;

private void resize();//创建一个新的数组,容量为之前的2倍,对旧数组中每一个不为空的Entry,重新计算在新数组中的位置,并防止到新数组中,更新table及相应的变量。

 

内部类:Entry继承自WeakReference

3、  ThreadLocal中方法的具体实现:

思路:首先通过Thread.currentThread()获得当前运行的线程t,然后通过t. threadLocals获得线程的ThreadLocalMap成员map,之后再调用ThreadLocalMap中的相应的方法更新或者查询map

public T get();

功能:返回当前线程内ThreadLocal变量的副本,如果map为空的话,先对map进行初始化

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();

    }

private T setInitialValue();

功能:初始化当前线程的ThreadLocalMap成员

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;

    }

 

void createMap(Thread t, T firstValue);

功能:具体的初始化函数

void createMap(Thread t, T firstValue) {

        t.threadLocals = new ThreadLocalMap(this, firstValue);

    }

 

public void set(T value);

功能:将<当前ThreadLocal, value>添加到当前线程的ThreadLocalMap中,如果ThreadLocalMap没有初始化的话,先进行初始化

public void set(T value) {

        Thread t = Thread.currentThread();

        ThreadLocalMap map = getMap(t);

        if (map != null)

            map.set(this, value);

        else

            createMap(t, value);

    }

 

public void remove();

功能:从当前线程的ThreadLocalMap中移除当前ThreadLocal对应的Entry

public void remove() {

         ThreadLocalMap m = getMap(Thread.currentThread());

         if (m != null)

             m.remove(this);

     }

 

ThreadLocalMap getMap(Thread t);

功能:返回线程tThreadLocalMap

ThreadLocalMap getMap(Thread t) {

        return t.threadLocals;

    }

 

4、  思路梳理

Thread中有一个ThreadLocalMap成员属性threadLocalsThreadLocal中有一个内部类ThreadLocalMap,以及成员属性和操作ThreadLocalMap的成员方法;

这些成员方法的工作流程为:

先获取当前运行的线程t,通过当前线程t获得线程的数据成员threadLocals,然后通过threadLocals调用ThreadLocalMap中的相应的方法完成对threadLocals的更新。


5、  结论

当线程调用ThreadLocal的相应方法操作变量时,实际上操作的是线程自身的局部变量,因此是线程封闭的,消除了竞争条件。

 

阅读更多
个人分类: Java后台
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭