ThreadLocal详解

1.ThreadLocal的使用

ThreadLocal,即线程变量,是一个以ThreadLocal对象为键,任意对象为值的存储结构。这个结构被附带在线程上,也就是说一个线程可以根据ThreadLocal对象查询到绑定到这个线程上的值。它的作用就是为每一个线程都创建一个变量副本,并且线程可以修改自己的变量副本,不影响其他线程的变量副本,使得各个线程之间的变量互不干扰。

如下代码:

public class ThreadLocalDemo {
    
    private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<Long>();
    
    public static final void begin(){
        TIME_THREADLOCAL.set(System.currentTimeMillis());
    }
    
    public static final long end(){
        return System.currentTimeMillis()-TIME_THREADLOCAL.get();
    }
    
    public static void main(String[] args) throws InterruptedException {
        ThreadLocalDemo.begin();
        TimeUnit.SECONDS.sleep(1);
        System.out.println(ThreadLocalDemo.end());
    }
}

运行结果:

1001

2.ThreadLocal内部结构

 

从上图可知:每个Thread内部都有一个Map,即ThreadLocalMap;ThreadLocalMap中存放ThreadLocal对象作为key,变量的副本作为value;Thread内部的Map是由ThreadLocal维护的,由Thread向Map中设置和获取对应线程的变量值。

3.源码分析

3.1 ThreadLocal.set方法

    public void set(T value) {
        Thread t = Thread.currentThread();
// ThreadLocal.ThreadLocalMap是线程t的一个变量,同时由源码可知,ThreadLocalMap底层是一个数组链表结构(和HashMap类似) ThreadLocalMap map
= getMap(t); if (map != null)
// 以ThreadLocal对象为key,要存放的对象value为value,存放在ThreadLocalMap中,进入该方法 map.set(
this, value); else createMap(t, value); }
     private void set(ThreadLocal key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            // 通过下标i来定位数组中对应的位置,然后判断是否存在相同的key值
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal k = e.get();
                // 如果存在相同的key值,则将value替换 
                if (k == key) {
                    e.value = value;
                    return;
                }
                // 如果key == null,则做另外一种处理
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            // 如果以上都不满足,则创建一个Entry对象
            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

3.2.ThreadLocal.get方法

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
// 根据ThreadLocal对象获取Entry对象 ThreadLocalMap.Entry e
= map.getEntry(this); if (e != null)
// 获取value
return (T)e.value; } return setInitialValue(); }

 

posted @ 2019-02-28 09:36  51life  阅读(...)  评论(... 编辑 收藏