ThreadLocal為什么要用WeakReference


先上一張圖看一下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);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM