');}

WeakReference

Author Avatar
Rico 11月 30, 2020

简介

在看ThreadLocal源码的时候,其中嵌套类ThreadLocalMap中的Entry继承了WeakReferenc,为了能搞清楚ThreadLocal,只能先了解下了WeakReferenc(是的,很多时候为了搞清楚一个东西,不得不往上追好几层,先搞清楚其所依赖的东西。)
WeakReference如字面意思,弱引用.

当一个对象仅仅被weak reference指向, 而没有任何其他strong reference指向的时候, 如果GC运行, 那么这个对象就会被回收, 不论当前的内存空间是否足够,这个对象都会被回收。

认识WeakReference类

WeakReference继承Reference,其中只有两个构造函数:

  1. public class WeakReference<T> extends Reference<T> {
  2. public WeakReference(T referent) {
  3. super(referent);
  4. }
  5. public WeakReference(T referent, ReferenceQueue<? super T> q) {
  6. super(referent, q);
  7. }
  8. }

WeakReference(T referent):referent就是被弱引用的对象(注意区分弱引用对象和被弱引用的对应,弱引用对象是指WeakReference的实例或者其子类的实例),比如有一个Apple实例apple,可以如下使用,并且通过get()方法来获取apple引用。也可以再创建一个继承WeakReference的类来对Apple进行弱引用,下面就会使用这种方式。

  1. WeakReference<Apple> appleWeakReference = new WeakReference<>(apple);
  2. Apple apple2 = appleWeakReference.get();

WeakReference(T referent, ReferenceQueue<? super T> q):与上面的构造方法比较,多了个ReferenceQueue,在对象被回收后,会把弱引用对象,也就是WeakReference对象或者其子类的对象,放入队列ReferenceQueue中,注意不是弱引用的对象,弱引用的对象已经被回收了。

实战

下面是使用继承WeakReference的方式来使用软引用,并且不使用ReferenceQueue。

  1. public class Fruit {
  2. private String name;
  3. public Fruit(String name) { this.name = name; }
  4. public String getName() { return name; }
  5. public void setName(String name) { this.name = name; }
  6. /**
  7. * 覆盖finalize,在回收的时候会执行。
  8. */
  9. @Override
  10. protected void finalize() throws Throwable {
  11. super.finalize();
  12. System.out.println("Fruit" + name + " finalize。");
  13. }
  14. @Override
  15. public String toString() {
  16. return "Fruit{" + "name='" + name + '\'' + '}' + ", hashCode:" + this.hashCode();
  17. }
  18. }
  1. public static void main(String[] args) {
  2. WeakReference<Fruit> weakReference = new WeakReference<>(new Fruit("红富士"));//注意到时候回收的是Fruit,而不是Apple
  3. //通过WeakReference的get()方法获取Apple
  4. System.out.println("调用weakference的toString:"+ weakReference.get());
  5. System.out.println("调用weakference的getName:"+ weakReference.get().getName());
  6. System.gc();
  7. try {
  8. //休眠一下,在运行的时候加上虚拟机参数-XX:+PrintGCDetails,输出gc信息,确定gc发生了。
  9. Thread.sleep(5000);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. //如果为空,代表被回收了
  14. if (weakReference.get() == null) {
  15. System.out.println("弱引用已经被回收");
  16. }
  17. }

可以看到,weakReference这个对象还在,但是它引用的Fruit已经没有了 。

还可以使用继承WeakReference的方式来使用软引用

沙拉引用了水果

  1. /**
  2. * Salad class 继承WeakReference,将Apple作为弱引用。
  3. * 注意到时候回收的是Fruit,而不是Salad
  4. */
  5. public class Salad extends WeakReference<Fruit> {
  6. public Salad(Fruit fruit) {
  7. super(fruit);
  8. }
  9. }
  1. public static void main(String[] args) {
  2. Salad salad = new Salad(new Fruit("红富士"));//注意到时候回收的是Fruit,而不是Salad
  3. //通过WeakReference的get()方法获取Apple
  4. System.out.println("调用salad的toString:"+ salad.get());
  5. System.out.println("调用salad的getName:"+ salad.get().getName());
  6. System.gc();
  7. try {
  8. //休眠一下,在运行的时候加上虚拟机参数-XX:+PrintGCDetails,输出gc信息,确定gc发生了。
  9. Thread.sleep(5000);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. //如果为空,代表被回收了
  14. if (salad.get() == null) {
  15. System.out.println("水果被回收了");
  16. }
  17. }

可以看到,沙拉还在,水果已经没有了。

ReferenceQueue的使用

  1. public static void main(String[] args) {
  2. ReferenceQueue<Fruit> fruitReferenceQueue = new ReferenceQueue<>();
  3. WeakReference<Fruit> fruitWeakReference = new WeakReference<Fruit>(new Fruit("草莓"), fruitReferenceQueue);
  4. WeakReference<Fruit> fruitWeakReference2 = new WeakReference<Fruit>(new Fruit("红苹果"), fruitReferenceQueue);
  5. System.out.println("=====gc调用前=====");
  6. Reference<? extends Fruit> reference = null;
  7. while ((reference = fruitReferenceQueue.poll()) != null ) {
  8. //不会输出,因为没有回收被弱引用的对象,并不会加入队列中
  9. System.out.println(reference);
  10. }
  11. System.out.println(fruitWeakReference);
  12. System.out.println(fruitWeakReference2);
  13. System.out.println(fruitWeakReference.get());
  14. System.out.println(fruitWeakReference2.get());
  15. System.out.println("=====调用gc=====");
  16. System.gc();
  17. try {
  18. Thread.sleep(5000);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. System.out.println("=====gc调用后=====");
  23. //下面两个输出为null,表示对象被回收了
  24. System.out .println(fruitWeakReference.get());
  25. System.out.println(fruitWeakReference2.get());
  26. //输出结果,并且就是上面的appleWeakReference、appleWeakReference2,再次证明对象被回收了
  27. Reference<? extends Fruit> reference2 = null;
  28. while ((reference2 = fruitReferenceQueue.poll()) != null ) {
  29. //如果使用继承的方式就可以包含其他信息了
  30. System.out.println("fruitReferenceQueue中:" + reference2);
  31. }
  32. }

This blog is under a CC BY-NC-SA 3.0 Unported License
本文链接:http://hogwartsrico.github.io/2020/11/30/WeakReference/