ThreadLocal爲何要用WeakReference

先上一張圖看一下ThreadLocal的內部結構,每一個Thread對象內部都維護了一個ThreadLocal.ThreadLocalMap數組

咱們在上圖看到的就是三個Thread對象內部格子的ThreadLocalMapide

這裏要說的不是ThreadLocal,是ThreadLocal爲何要用WeakReferencethis

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

弱引用WeakReference

弱引用只要發生了gc就會被回收,但前提是隻有弱引用,沒有強引用(這點自己也不容易作到)spa

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

引用傳遞的特殊狀況

一、傳遞的入參是null,方法內new了,也不會影響到外面null的對象,仍是null的
二、傳遞的入參不是null,方法內=null了,也不會影響到外面不是null的對象
三、傳遞的入參不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 不用有什麼問題code

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);
相關文章
相關標籤/搜索