Java四种引用方式
强引用
Object object= new Object();
这种方式就是强引用,强引用在任何时候都不会被jvm回收,即使抛出OutOfMemoryError。
object=null; //这时候object会被gc回收
System.gc(); // 手动调用,垃圾回收器会回收没有任何被引用的对象
垃圾回收之前会调用finallize方法
软引用
Object object= new Object();
SoftReference softReference = new SoftReference<>(object);
Object result = softReference.get();
通过SoftReference的get方法来获取对象。软引用,在jvm内存不足的情况下会被回收。
这里面有两个两个对象,softReference指向SoftReference是强引用,object指向SoftReference是软引用
适用场景:软引用缓存使用
弱引用
WeakReference weakReference= new WeakReference<>(object);
Object result = weakReference.get();
通过WeakReference的get方法来获取对象。在gc的时候就会被回收,不管内存是否充足。
虚引用
Object object= new Object();
ReferenceQueue queue = new ReferenceQueue();
PhantomReference pr = new PhantomReference(object, queue);
虚引用和没有引用是一样的,需要和队列(ReferenceQueue)联合使用。当jvm扫描到虚引用的对象时,会先将此对象放入关联的队列中,因此我们可以通过判断队列中是否存这个对象,来进行回收前的一些处理。
ThreadLocal和WeakReference关系
ThreadLocal tl=new ThreadLocal();
ThreadLocal:线程本地对象
线程T1->run方法,run方法->A方法->B方法 一个线程内方法的调用,栈允许的话,方法可以无限调用
这个ThreadLocal可以认为是这个线程的全局变量,这个线程内所有方法都可以访问它。
看下代码:
// 这里set key是ThreadLocal对象,vaule是值
这里的threadlocals是个map,相当于是线程的容器
线程池:线程用完归还回去,一个线程正常运行完之后,如果在这个线程里涉及ThreadLocal,务必要清空ThreadLocal,这里可能涉及内存泄漏
线程池运行越来越长,不清理的话,内存越占越大,T1线程是不死的,在线程池里。
tl.remove() // 删除key,value
还有问题是当前业务直接get,通过key获取value,其他业务来也通过key获取value,用的是旧的值。
案例;spring @transactional注解
method方法里调用A,B,C方法,这里每个方法要注入数据库连接,这些connection要想组装成一个完整的事务,必须是同一个connection,如何保证在同一个connection里,就是在method调用的时候,把connection放进ThreadLocal,A,B,C方法从ThreadLocal里面取。
说了这么多,ThreadLocal和弱引用有毛线关系?
ThreadLocal作为key,value就是set进去的值
最终的设定是:
这里的Entry继承了WeakReference,终于和弱引用挂钩了
这里的tl只要栈弹出就会被回收,如果key指向ThreadLocal是强引用,就不会被回收。
下一篇,深入ThreadLocal源码。