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(); }
  • 相关阅读:
    Java中NIO和IO区别和适用场景
    JDK和CGLIB动态代理原理
    java中的Serializable接口的作用
    redis采用序列化方案存对象
    在时间复杂度为O(n)且空间复杂度为O(1)的情况下翻转链表
    给定一个排好序的数组,然后求出丢失的数字
    求字符串里超过字符长度一半的元素
    求你给定两字符串包含的字母数是否完全一致
    动态规划,求数组不相邻数字的最大子串值
    JWT 工具
  • 原文地址:https://www.cnblogs.com/51life/p/10429506.html
Copyright © 2011-2022 走看看