Java并发之ThreadLocal

前言

ThreadLocal是一个全局变量,用于解决线程范围内变量共享问题,其实ThreadLocal可以看作是一个Map集合,而key就是当前线程名,而value是想要存放的变量,ThreadLocal的变量用完会自动销毁,不用考虑ThreadLocal中的变量会占用空间,对于ThreadLocal来说每个线程的变量都是独立的,不会相互影响,可以通过ThreadLocal在同一线程内的不同组件传递公共变量

成员变量

我们看ThreadLocal的源码可以看到他有三个成员变量

/**
    这个属性用于ThreadLocal的桶位寻址
    如果一个threadLocal对象第一次调用get()方法,那么就会给当前线程分配一个value
    这个value和这个threadLocal对象被包装成一个entry
    这个entry的key是threadLocal对象,value是生成的value
    **/ private final int threadLocalHashCode = nextHashCode(); /**
    这个属性是创建ThreadLocal会用到该属性
    每创建一个ThreadLocal对象,就会使用该属性分配一个hash值给这个对象
    **/ private static AtomicInteger nextHashCode = new AtomicInteger(); /**
    表示hash增量,没创建一个ThreadLocal对象,ThreadLocal.nextHashCode就会增长HASH_INCREMENT
    **/ private static final int HASH_INCREMENT = 0x61c88647;

get方法

public T get() { //获取当前线程 Thread t = Thread.currentThread(); //根据当前线程获取ThreadLocalMap对象 ThreadLocalMap map = getMap(t); //判断map是否为null if (map != null) { //当前threadLocal对象作为key获取entry ThreadLocalMap.Entry e = map.getEntry(this); //判断entry是否为null if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value; //返回result return result;
        }
    } //初始化 return setInitialValue();
}

接下来我们再看这个初始化方法

setInitialValue方法

这个方法是用于初始化的,我们从上面的get方法可以知道,进入该方法有两种情况,一个就是ThreadLocalMap为null或者Entry为null

private T setInitialValue() { //调用ThreadLocal对象的方法进行初始化 T value = initialValue(); //获取到当前线程 Thread t = Thread.currentThread(); //当前线程作为key获取ThreadLocalMap对象 ThreadLocalMap map = getMap(t); //判断map是否为null,如果不为null证明已经初始化过ThreadLocalMap对象了(一个ThreadLocal只会初始化一次) if (map != null) //向ThreadLocalMap中保存当前threadLocal与当前线程生成的线程局部变量 map.set(this, value); else //如果走到这里证明map==null,进行初始化创建一个ThreadLocalMap对象 createMap(t, value); return value;
    }

set方法

public void set(T value) { //获取当前线程 Thread t = Thread.currentThread(); //将当前线程作为key获取ThreadLocalMap对象 ThreadLocalMap map = getMap(t); //判断threadLocalMap是否为null if (map != null) //覆盖或者添加新的key - value map.set(this, value); else //证明还没有被初始化,进行初始化 createMap(t, value);
}

如何实现线程隔离?

每一个Thread都有着自己的ThreadLocalMap用于存储数据,当线程访问某个ThreadLocal对象的get方法的时候,方法内部会判断该线程的ThreadLocalMap数组内是否存在以当前线程为key的Entry节点,如果数组内没有对应的节点,那么当前ThreadLocal对象,就会调用初始化方法,创建一个Entry节点放入ThreadLocalMap中

ThreadLocal内存泄漏原因

主要是因为ThreadLocalMap的Entry对象是弱引用,对于弱引用,JVM在每次GC的时候都会清理他们,此时key就会变为null,如果此时没有其他强引用指向value,那么此时value就不会被访问到,按道理来说value应该也会被GC,但是此时ThreadLocalMap的Entry对象对value是强引用,这样就会导致JVM始终无法GC value,这样就导致了value成了一个始终无法清理的value

#Java##程序员#
全部评论
请问楼主该如何防止内存泄漏
点赞 回复 分享
发布于 2022-08-26 20:02 陕西

相关推荐

ArisRobert:统一解释一下,第4点的意思是,公司按需通知员工,没被通知到的员工是没法去上班的,所以只要没被通知到,就自动离职。就是一种比较抽象的裁员。
点赞 评论 收藏
分享
10-15 09:13
已编辑
天津大学 soc前端设计
点赞 评论 收藏
分享
点赞 2 评论
分享
牛客网
牛客企业服务