ThreadLocal详解

ThreadLocal

当创建一个ThreadLocal后,在某个线程中调用set()方法时,ThreadLocal会从当前线程中获得ThreadLocalMap 对象 threadLocals,threadLocals相当于一个Map,它是用数组存储对象的。每一个Entry中保存了key和value,其中key就是ThreadLocal对象,value就是我们要保存的值。其中key是一个弱引用(如果没有其他引用,例如在其他栈中的强引用或者软引用,下一次gc就会回收说引用的对象)
threadLocals根据threadLocal中的threadLocalHashCodehu值, 经过运算获得table中下标。(这里不讨论hash冲突问题)
继承关系: Entry 继承 WeakReference ,WeakReference 继承 Reference。在Reference中的有一个私有字段referent 保存传入的key。

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

    Entry(ThreadLocal<?> k, Object v) {
        // 将key在Reference的referent字段
        super(k);
        value = v;
    }
}

在这里插入图片描述
当栈中的Thread Ref 引用回收后,此时key为null,而object已经不再使用,需要回收,但他被value强引用,只要线程不结束(例如使用线程池),就会存在一条从栈到object的强引用链,故object无法被gc回收。ThreadLocal的解决办法是在set,get,和remove时,移除key为null的 value对象。还有另外一个可能造成内存泄露的问题。如果ThreadLocal Ref 一直存在(例如把他声明为static变量),但保存对象obje的ct又不需要使用,那么也会造成内存泄露所以最好办法就是及时把不需要的变量移除。
在这里插入图片描述
下面这个例子可以帮助理解:

package com.deng;

import java.lang.ref.WeakReference;
/**
 * @author :deng
 * @version :1.0
 * @description :
 * @since :1.8
 */
public class T {


    static class Task implements Runnable {
        WeakReference<ThreadLocal> threadLocalWeakReference;

        public void fun() {
            // 这里是对ThreadLocal 的强引用
            ThreadLocal<Object> threadLocal1 = new ThreadLocal<Object>();
            Object o = new Object();
            System.out.println(o);
            threadLocal1.set(o);
            // 这里是虚引用
            WeakReference<ThreadLocal> threadLocalWeakReference = new WeakReference<ThreadLocal>(threadLocal1);
            // 将虚引用保存
            this.threadLocalWeakReference = threadLocalWeakReference;
        }

        public void fun2() {
            System.out.println(threadLocalWeakReference.get());
        }


        @Override
        public void run() {
            fun();
            // fun() 结束后,对 ThreadLocal的强引用threadLocal1就结束了,
            // 那么对threadLocal对象的引用就只剩弱引用了
            // gc,如果成功的话,那么就会回收threadLocal所引用的对象
            System.gc();
            fun2();
        }
    }


    public static void main(String[] args) throws Exception {
        Task task = new Task();
        new Thread(task).start();
    }

}

// 结果
// java.lang.Object@6a6daa45
// null
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值