先上一张图看一下ThreadLocal的内部结构,每个Thread对象内部都维护了一个ThreadLocal.ThreadLocalMap
我们在上图看到的就是三个Thread对象内部格子的ThreadLocalMap
这里要说的不是ThreadLocal,是ThreadLocal为什么要用WeakReference
static class ThreadLocalMap { static class Entry extends WeakReference> { Entry(ThreadLocal k, Object v) { super(k); value = v; }
弱引用WeakReference
弱引用只要发生了gc就会被回收,但前提是只有弱引用,没有强引用(这点本身也不容易做到)
WeakReferenceweakReference = new WeakReference<>(new Apple("1"));try { Thread.sleep(2000L);} catch (InterruptedException e) { e.printStackTrace();}System.out.println(weakReference.get());//1System.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);}@Datastatic class ObjectPassing{ private String name;}1:null2:ParameterPassing.ObjectPassing(name=zxp)3:null=======================1:ParameterPassing.ObjectPassing(name=name)2:null3:ParameterPassing.ObjectPassing(name=name)=======================1:name1:name2:null1:name1:name1: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();//执行GCt = 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);