先上一張圖看一下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; }
弱引用只要發生了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 不用有什麼問題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);