美文网首页
ThreadLocal源码解读

ThreadLocal源码解读

作者: Android_小马范儿 | 来源:发表于2019-05-30 16:13 被阅读0次

    ThreadLocal的场景是用来隔离各个线程的局部变量,各个线程之间的数值互不干扰。
    先查看个例子:

        final ThreadLocal<Boolean> threadLocal = new ThreadLocal<>();
            threadLocal.set(true);
            Log.e(TAG, Thread.currentThread()+"="+threadLocal.get());
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG, Thread.currentThread()+"="+threadLocal.get());
                }
            }).start();
    

    执行的结果如下:

    Thread[main,5,main]=true
    Thread[Thread-5,5,main]=null
    

    从结果看 主线程和子线程获取的threadLocal值不同,所以应用于线程数据隔离

    源码查看Set(true)方法

        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
    //获取线程对应的ThreadLocalMap
        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    
    //ThreadLocal变量跟对象实例firstValue由线程的threadLocals来维护
       void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    
      private void set(ThreadLocal<?> key, Object value) {
    
                // We don't use a fast path cas with get() beause 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;  //table是ThreadMap内的Entry数组
                int len = tab.length;
                int i = key.threadLocalHashCode & (len-1);  //获取hash值,用于数组中的小标
    
                for (Entry e = tab[i];
                     e != null;
                     e = tab[i = nextIndex(i, len)]) {
      //如果数组中有对应的值则进入
                    ThreadLocal<?> k = e.get();
            //key值相等则覆盖值
                    if (k == key) {
                        e.value = value;
                        return;
                    }
     //此时说明此处 Entry 的 k 中的对象实例已经被回收了,需要替换掉这个位置的 key 和 value
                    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();
            }
    

    源码查看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()方法就是根据所在线程获取ThreadLocalMap,根据TheadLocal获取对应的ThreadLocalMap.Entry,然后获取对应的value值,否则返回setInitialValue()=null

    相关文章

      网友评论

          本文标题:ThreadLocal源码解读

          本文链接:https://www.haomeiwen.com/subject/fjlvtctx.html