WeakReference
阅读原文请访问我的博客 BrightLoong's Blog https://brightloong.github.io/2018/05/27/关于Java中的WeakReference/#more
一. 简介
在看 ThreadLocal 源码的时候, 其中嵌套类 ThreadLocalMap 中的 Entry 继承了 WeakReferenc, 为了能搞清楚 ThreadLocal, 只能先了解下了 WeakReferenc(是的, 很多时候我了搞清楚一个东西, 不得不往上追好几层, 先搞清楚其所依赖的东西.)
下面进入正题, WeakReference 如字面意思, 弱引用, 当一个对象仅仅被 weak reference(弱引用)指向, 而没有任何其他 strong reference(强引用)指向的时候, 如果这时 GC 运行, 那么这个对象就会被回收, 不论当前的内存空间是否足够, 这个对象都会被回收.
二. 认识 WeakReference 类
WeakReference 继承 Reference, 其中只有两个构造函数:
- public class WeakReference<T> extends Reference<T> {
- public WeakReference(T referent) {
- super(referent);
- }
- public WeakReference(T referent, ReferenceQueue<? super T> q) {
- super(referent, q);
- }
- }
WeakReference(T referent):referent 就是被弱引用的对象 (注意区分弱引用对象和被弱引用的对应, 弱引用对象是指 WeakReference 的实例或者其子类的实例), 比如有一个 Apple 实例 apple, 可以如下使用, 并且通过 get() 方法来获取 apple 引用. 也可以再创建一个继承 WeakReference 的类来对 Apple 进行弱引用, 下面就会使用这种方式.
- WeakReference<Apple> appleWeakReference = new WeakReference<>(apple);
- Apple apple2 = appleWeakReference.get();
WeakReference(T referent, ReferenceQueue<? super T> q): 与上面的构造方法比较, 多了个 ReferenceQueue, 在对象被回收后, 会把弱引用对象, 也就是 WeakReference 对象或者其子类的对象, 放入队列 ReferenceQueue 中, 注意不是被弱引用的对象, 被弱引用的对象已经被回收了.
三. 使用 WeakReference
下面是使用继承 WeakReference 的方式来使用软引用, 并且不使用 ReferenceQueue.
简单类 Apple
- package io.github.brightloong.lab.reference;
- /**
- * Apple class
- *
- * @author BrightLoong
- * @date 2018/5/25
- */
- public class Apple {
- private String name;
- public Apple(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- /**
- * 覆盖 finalize, 在回收的时候会执行.
- * @throws Throwable
- */
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- System.out.println("Apple:" + name + "finalize.");
- }
- @Override
- public String toString() {
- return "Apple{" +
- "name='" + name + '\'' +
- '}' + ", hashCode:" + this.hashCode();
- }
- }
继承 WeakReference 的 Salad
- package io.github.brightloong.lab.reference;
- import java.lang.ref.WeakReference;
- /**
- * Salad class
- * 继承 WeakReference, 将 Apple 作为弱引用.
- * 注意到时候回收的是 Apple, 而不是 Salad
- *
- * @author BrightLoong
- * @date 2018/5/25
- */
- public class Salad extends WeakReference<Apple> {
- public Salad(Apple apple) {
- super(apple);
- }
- }
Clent 调用和输出
- package io.github.brightloong.lab.reference;
- import java.lang.ref.WeakReference;
- /**
- * Main class
- *
- * @author BrightLoong
- * @date 2018/5/24
- */
- public class Client {
- public static void main(String[] args) {
- Salad salad = new Salad(new Apple("红富士"));
- // 通过 WeakReference 的 get()方法获取 Apple
- System.out.println("Apple:" + salad.get());
- System.gc();
- try {
- // 休眠一下, 在运行的时候加上虚拟机参数 - XX:+PrintGCDetails, 输出 gc 信息, 确定 gc 发生了.
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // 如果为空, 代表被回收了
- if (salad.get() == null) {
- System.out.println("clear Apple.");
- }
- }
- }
输出如下:
- Apple:Apple{name='红富士'}, hashCode:1846274136
- [GC (System.gc()) [PSYoungGen: 3328K->496K(38400K)] 3328K->504K(125952K), 0.0035102 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
- [Full GC (System.gc()) [PSYoungGen: 496K->0K(38400K)] [ParOldGen: 8K->359K(87552K)] 504K->359K(125952K), [Metaspace: 2877K->2877K(1056768K)], 0.0067965 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Apple: 红富士 finalize.
clear Apple.
ReferenceQueue 的使用
- package io.github.brightloong.lab.reference;
- import java.lang.ref.Reference;
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.WeakReference;
- /**
- * Client2 class
- *
- * @author BrightLoong
- * @date 2018/5/27
- */
- public class Client2 {
- public static void main(String[] args) {
- ReferenceQueue<Apple> appleReferenceQueue = new ReferenceQueue<>();
- WeakReference<Apple> appleWeakReference = new WeakReference<Apple>(new Apple("青苹果"), appleReferenceQueue);
- WeakReference<Apple> appleWeakReference2 = new WeakReference<Apple>(new Apple("毒苹果"), appleReferenceQueue);
- System.out.println("=====gc 调用前 =====");
- Reference<? extends Apple> reference = null;
- while ((reference = appleReferenceQueue.poll()) != null ) {
- // 不会输出, 因为没有回收被弱引用的对象, 并不会加入队列中
- System.out.println(reference);
- }
- System.out.println(appleWeakReference);
- System.out.println(appleWeakReference2);
- System.out.println(appleWeakReference.get());
- System.out.println(appleWeakReference2.get());
- System.out.println("===== 调用 gc=====");
- System.gc();
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("=====gc 调用后 =====");
- // 下面两个输出为 null, 表示对象被回收了
- System.out.println(appleWeakReference.get());
- System.out.println(appleWeakReference2.get());
- // 输出结果, 并且就是上面的 appleWeakReference,appleWeakReference2, 再次证明对象被回收了
- Reference<? extends Apple> reference2 = null;
- while ((reference2 = appleReferenceQueue.poll()) != null ) {
- // 如果使用继承的方式就可以包含其他信息了
- System.out.println("appleReferenceQueue 中:" + reference2);
- }
- }
- }
结果输出如下:
=====gc 调用前 =====
- java.lang.ref.WeakReference@6e0be858
- java.lang.ref.WeakReference@61bbe9ba
- Apple{name='青苹果'}, hashCode:1627674070
- Apple{name='毒苹果'}, hashCode:1360875712
===== 调用 gc=====
Apple: 毒苹果 finalize.
Apple: 青苹果 finalize.
=====gc 调用后 =====
null
null
appleReferenceQueue 中: java.lang.ref.WeakReference@6e0be858
appleReferenceQueue 中: java.lang.ref.WeakReference@61bbe9ba
Process finished with exit code 0
可以看到在队列中(ReferenceQueue), 调用 gc 之前是没有内容的, 调用 gc 之后, 对象被回收了, 并且弱引用对象 appleWeakReference 和 appleWeakReference2 被放入了队列中.
来源: http://www.jianshu.com/p/964fbc30151a