ThreadLocal为什么要用WeakReference

ThreadLocal为什么要用WeakReference先上一张图看一下ThreadLocal的内部结构,每个Thread对象内部都维护了一个ThreadLocal.ThreadLocalMap 我们在上图看到的就是三个Thread对象内部格子的Threa

image.png 先上一张图看一下ThreadLocal的内部结构,每个Thread对象内部都维护了一个ThreadLocal.ThreadLocalMap

我们在上图看到的就是三个Thread对象内部格子的ThreadLocalMap

这里要说的不是ThreadLocal,是ThreadLocal为什么要用WeakReference

static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }

弱引用WeakReference

弱引用只要发生了gc就会被回收,但前提是只有弱引用,没有强引用(这点本身也不容易做到)

WeakReference<Apple> weakReference = new WeakReference<>(new Apple("1"));
try {
    Thread.sleep(2000L);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println(weakReference.get());//1
System.gc();//遇到gc就回收了
System.out.println(weakReference.get());//null

引用传递的特殊情况

1、传递的入参是null,方法内new了,也不会影响到外面null的对象,还是null的 2、传递的入参不是null,方法内=null了,也不会影响到外面不是null的对象 3、传递的入参不null,传递到线程中,线程运行中,外面把入参设置为null,线程内继续不是null 总结,别管里面外面 null变!null !null变null 都不会隔层影响原来啥样还啥样

//我们在这里只插入一段模拟线程运行的情况    ……
    obj = new ObjectPassing();
    obj.setName("name");
    MyThread myThread = new MyThread(obj);//obj不是空的传入新线程
    new Thread(myThread).start();//线程不停的打印obj的name字段值
    Thread.sleep(1000);
    obj = null;//将外面的obj置为空后,线程打印的仍然不为空,这点需要先明确
    System.out.println("2:"+obj);

    Thread.sleep(1000000);
}

public void testNullPassFunc(ObjectPassing obj){
    obj = new ObjectPassing();
    obj.setName("zxp");
    System.out.println("2:"+obj);
}

public void testNullPassFunc2(ObjectPassing obj){
    obj = null;
    System.out.println("2:"+obj);
}

@Data
static class ObjectPassing{
    private String name;
}

1:null
2:ParameterPassing.ObjectPassing(name=zxp)
3:null
=======================
1:ParameterPassing.ObjectPassing(name=name)
2:null
3:ParameterPassing.ObjectPassing(name=name)
=======================
1:name
1:name
2:null
1:name
1:name
1:name
……
public class MyThread implements Runnable {
    ParameterPassing.ObjectPassing objectPassing = null;
    public MyThread(ParameterPassing.ObjectPassing objectPassing){
        this.objectPassing = objectPassing;
    }

    @Override
    public void run() {
        while (true){
            System.out.println("1:"+objectPassing.getName());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

分析ThreadLocal与WeakReference

分析一下为什么ThreadLocal要用WeakReference 不用有什么问题

ThreadLocal local = new ThreadLocal();
local.set("当前线程名称:"+Thread.currentThread().getName());//将ThreadLocal作为key放入threadLocals.Entry中
Thread t = Thread.currentThread();//注意断点看此时的threadLocals.Entry数组刚设置的referent是指向Local的,referent就是Entry中的key只是被WeakReference包装了一下
local = null;//断开强引用,即断开local与referent的关联,但Entry中此时的referent还是指向Local的,为什么会这样,当引用传递设置为null时无法影响传递内的结果
System.gc();//执行GC
t = Thread.currentThread();//这时Entry中referent是null了,被GC掉了,因为Entry和key的关系是WeakReference,并且在没有其他强引用的情况下就被回收掉了
//如果这里不采用WeakReference,即使local=null,那么也不会回收Entry的key,因为Entry和key是强关联
//但是这里仅能做到回收key不能回收value,如果这个线程运行时间非常长,即使referent GC了,value持续不清空,就有内存溢出的风险
//彻底回收最好调用remove
//即:local.remove();//remove相当于把ThreadLocalMap里的这个元素干掉了,并没有把自己干掉
System.out.println(local);

今天的文章ThreadLocal为什么要用WeakReference分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22157.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注