zoukankan      html  css  js  c++  java
  • ThreadLocal源码简读

    先说一下,本篇文章,只是简单,阅读下源码,应对面试差不多够了,要深入理解,还请看源码

    讲实话,看完源码,还是有点小迷,ThreadLocal源码,感觉优点乱。。

    每个线程中都可以通过ThreadLocal定义一个独立的副本,不会影响到其他线程;

    ThreadLocal主要属性和方法

    1. 一个静态内部类:ThreadLocalMap

      • 维护了一个静态内部类Entry,Entry类下有一个value属性,就是存储线程通过ThreadLocal放的值;

      • 维护了一个Entry[ ] table数组;

        此数组里面存放的是线程对象;

      • 这里注意:Entry是弱引用,最后会说一下,弱引用使用场景;

    2. get方法,后面说

    3. set方法,后面说

    下面是提取出来的主要的源码:

    public class ThreadLocal<T> {
        static class ThreadLocalMap {
            // 每个线程一个Entry,对应唯一的Value,弱引用对象
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
            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);
            }
        }
        // 设置值,后面讲
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
        // 主要是getEntry方法!后面会详解
        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();
        }
        // 我们在set值的时候,ThreadLocalMap一般是没有创建的
        // 而是通过createMap(t, value);创建一个
        // 这个初始化,会直接通过构造方法,把要放的值,放进去!
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
        // 删除,直接删除线程对应的Entry对象
        public void remove() {
            ThreadLocalMap m = getMap(Thread.currentThread());
            if (m != null)
                m.remove(this);
        }
    }
    

    还要知道:

    每一个Thread对象下都有一个ThreadLocalMap对象:

    public class Thread implements Runnable {
    	ThreadLocal.ThreadLocalMap threadLocals = null;
      	......
    }
    

    get、set

    1. ThreadLocalMap下维护一个table数组,初始容量为16;

    2. 提供set()方法:

      根据线程对象,拿到此TheadLocal下的ThreadLocalMap对象

      ThreadLocalMap对象只有一个!

      map.getEntry根据线程ID,锁定线程对应的Entry对象;

      找到这个Entry对象,拿到里面的value,就是此线程存放的值;

      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();
      }
      
    3. set()方法

      比较简单;不说了。。

      public void set(T value) {
          Thread t = Thread.currentThread();
          ThreadLocalMap map = getMap(t);
          if (map != null)
              map.set(this, value); // 这里是key是线程对象,value是要村的值
          else
              createMap(t, value);
      }
      

    弱引用Entry

    Entry对象是弱引用!!存在内存泄露风险!

    弱引用:GC触发,就会回收的对象!

    所以,只能用于临时存储,即存即用的场景,如果是强依赖这个副本,则不适合使用ThreadLocal

  • 相关阅读:
    Magento2 观察者模式 之 插件
    Magento2 自定义生成日志函数
    magento 由于Httpd进程增多,导致CPU占用100%问题
    Magento composer 安装
    htaccess 的使用基本小节 For apache httpd
    设计便捷命令行工具列表
    docker-lnmp dockerfile
    使用Portainer管理Docker
    关于IIS站点最大并发量分析
    深入理解IIS的多线程工作机制
  • 原文地址:https://www.cnblogs.com/mussessein/p/12762087.html
Copyright © 2011-2022 走看看