zoukankan      html  css  js  c++  java
  • ThreadLocal总结(jdk1.8源码)

    ThreadLocal为每个使用它的线程提供一个变量的副本。
    ThreadLocal中的主要方法:
     
    1. public void set(T value)
     
    public void set(T value) {
            Thread t = Thread.currentThread();
             //取得线程t的ThreadLocalMap对象
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
     
         先调用Thread类的静态方法获得当前线程的Thread对象,每个线程对应的Thread对象都有一个ThreadLocalMap对象的引用,如下。
        
      ThreadLocal.ThreadLocalMap threadLocals = null;     //Thread类中
         然后获得当前线程的ThreadLocalMap对象
    ThreadLocalMap getMap(Thread t) {     //ThreadLocal类内的方法
            return t.threadLocals;
        }
         如果不为空就调用set方法,如果为空就调用createMap方法,传入参数为ThreadLocalMap为空的Thread对象,和T类型的firstValue
     void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    使用ThreadLocalMap的重载构造器,构造Thread对象的ThreadLocalMap,传入参数为当前的ThreadLocal对象,和firstValue
     private static final int INITIAL_CAPACITY = 16;          //ThreadLocalMap中定义的
     
     private final int threadLocalHashCode = nextHashCode();          //ThreadLocal中定义的
     
     ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
                table = new Entry[INITIAL_CAPACITY];
                int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
                table[i] = new Entry(firstKey, firstValue);
                size = 1;
                setThreshold(INITIAL_CAPACITY);
            }
    i为threadLocal对象的哈希值和Entry数组的大小-1的二进制值(1111)的操作结果,这样能保证存储在数组的每一个位置的概率相同。
    创建一个Entry(键值对)数组,存放下标为threadLocal对象的哈希值和1111的与操作结果,存放对象的键为threadLocal对象,值为firstValue即set的值
     
    firstValue对象存储在ThreadLocalMap对象维护的Entry类型数组 table内,下标为ThreadLocal对象和1111的与运算结果,entry的key为threadLocal对象
     
    2.public Object get()方法:该方法返回当前线程所对应的线程局部变量
     
     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();
        }
    get方法,先获取当前线程的thread对象,再获取thread对象的threadLocalMap对象,然后根据当前的threadLocal对象取得table数组对应下标的Entry对象(因为存储的时候就是根据当前的ThreadLoca对象的Hash值存储的)
    private Entry getEntry(ThreadLocal<?> key) {
                int i = key.threadLocalHashCode & (table.length - 1);
                Entry e = table[i];
                if (e != null && e.get() == key)
                    return e;
                else
                    return getEntryAfterMiss(key, i, e);
            }
    最后如果Thread对象的ThreadLocalMap为空的话,就调用setInitialValue方法,该方法初始化map并且放入null ( initialValue的返回值为null ),可以通过覆盖该方法修改没有set的时候的初始值
       
     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;
        }
     
     
    3.public void remove()方法
     public void remove() {
             ThreadLocalMap m = getMap(Thread.currentThread());
             if (m != null)
                 m.remove(this);
         }
     
    ThreadLocal的remove方法先获取当前线程的Map对象,然后调用Map的remove方法,删除entry
     
    总结:
              对于非线程安全的变量可以将它封装进ThreadLocal中,在调用的时候不是直接引用而是使用ThreadLocal的set和get方法
              
              线程调用set方法:
              放入当前线程的ThreadLocalMap中,key为ThreadLocal的hashCode
  • 相关阅读:
    541. Reverse String II
    540. Single Element in a Sorted Array
    初识python
    openCV
    openCV
    win环境下安装配置openCV-4.3.0
    力扣Leetcode 198. 打家劫舍
    力扣Leetcode 680. 验证回文字符串 Ⅱ
    力扣Leetcode 560. 和为K的子数组
    华师2019软件专硕复试机试题最后一题G:找数
  • 原文地址:https://www.cnblogs.com/coderlynn/p/8654473.html
Copyright © 2011-2022 走看看