Java-ThreadLocal解析与源码分析

Java-ThreadLocal解析与源码分析

解析

ThreadLocal和Synchronized都用于解决多线程并发访问,synchronized 是利用锁的机制,使变量或代码块在某一时该仅仅能被一个线程訪问。而ThreadLocal 为每个线程都提供了变量的副本,使得每个线程在某一时间訪问到的并非同一个对象,这样就隔离了多个线程对数据的数据共享。

Spring的事务就借助了ThreadLocal,Spring从数据库连接池取得一个Connection,将connection放到ThreadLocal,也就和线程绑定了,事务需
要提交或者回滚,只要从ThreadLocal 中拿到connection 进行操作。

源码解析

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();
  }
 ThreadLocalMap getMap(Thread t) {
       return t.threadLocals;
   }

上面先取到当前线程,然后调用getMap 方法获取对应的ThreadLocalMap,
ThreadLocalMap 是ThreadLocal 的静态内部类,然后Thread 类中有一个这样类型成员,所以getMap 是直接返回Thread 的成员。

static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table;

Entry 内部静态类,它继承了WeakReference,总之它记录了两个信息,一个是ThreadLocal<?>类型,一个是Object 类型的值。getEntry 方法则是获取某个ThreadLocal 对应的值,set 方法就是更新或赋值相应的ThreadLocal对应的值。
get 方法,其实就是拿到每个线程独有的ThreadLocalMap,然后再用ThreadLocal 的当前实例,拿到Map 中的相应的Entry,然后就可以拿到相应的值返回出去。当然,如果Map 为空,还会先进行map 的创建,初始化等工作。

ThreadLocal内存泄露分析

我们前面对ThreadLocal 的分析,我们可以知道每个Thread 维护一个
ThreadLocalMap,这个映射表的key 是ThreadLocal 实例本身,value 是真正需要存储的Object,也就是说ThreadLocal 本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap 获取value。仔细观察ThreadLocalMap,这个map是使用ThreadLocal 的弱引用作为Key 的,弱引用的对象在GC 时会被回收。
在这里插入图片描述
这样,当把threadlocal 变量置为null 以后,没有任何强引用指向threadlocal实例,所以threadlocal 将会被gc 回收。这样一来,ThreadLocalMap 中就会出现key 为null 的Entry,就没有办法访问这些key 为null 的Entry 的value,如果当前线程再迟迟不结束的话,这些key 为null 的Entry 的value 就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,而这块value 永远不会被访问到了,所以存在着内存泄露。
只有当前thread 结束以后,current thread 就不会存在栈中,强引用断开,Current Thread、Map value 将全部被GC 回收。最好的做法是不在需要使用ThreadLocal 变量后,都调用它的remove()方法,清除数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值