zoukankan      html  css  js  c++  java
  • 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(); }
  • 相关阅读:
    spring注解
    SVN cleanup 反复失败解决办法
    如何改变cmd窗口大小
    JQuery UI
    VS2013装扩展RazorGenerator
    visual studio 2013使用github获取代码
    还原NuGet程序包
    C# linq对分组操作执行子查询
    C# linq创建嵌套组
    linq 在查询表达式中处理异常
  • 原文地址:https://www.cnblogs.com/51life/p/10429506.html
Copyright © 2011-2022 走看看