@lemonguge
2017-09-13T14:50:49.000000Z
字数 3648
阅读 427
JAVA
Java中的有四种引用方式:强引用、软引用、弱引用、虚引用。
new这个关键字创建对象时,被创建的对象具有强引用。Object obj = new Object();代码中的obj就是强引用,垃圾回收器就不会去回收有强引用的对象。当JVM内存不足时,具备强引用的对象,虚拟机宁可会报内存空间不足的异常来终止程序,也不会靠垃圾回收器去回收该对象来解决内存问题。JDK1.2以前是没有这些概念,在JDK1.2以后的版本中才开始引入了引用的四种级别依次是,强引用、软引用、弱引用和虚引用。JDK中java.lang.ref.Reference类就是Java引用抽象基类,Reference类定义了引用对象的操作。当然该类是与垃圾回收器配合使用的。
有三个导出类继承自Reference类,它们分别代表着软引用、弱引用和虚引用。
java.lang.ref.SoftReferencejava.lang.ref.WeakReferencejava.lang.ref.PhantomReference查看体系中的顶层类,可以了解该体系的基本功能。所以我们先学习Reference这个抽象基类,这个类比较简单,封装了四个方法。
clear()方法:清除此引用对象。(常用)get()方法:返回此引用对象的指示对象。(常用)enqueue()方法:将此引用对象添加到引用对象已向其注册的队列(如果有)。(由GC调用该方法)isEnqueued()方法:由程序或垃圾回收器通知是否已将此引用对象加入队列。(判断对象是否被回收)了解Reference类中的clear()方法和get()方法就可以了,然后我们学习体系中的那三个引用实现类。
get()方法。 SoftReference(T referent):创建引用给定对象的新的软引用,新的引用没有向任何队列注册。SoftReference(T referent, ReferenceQueue<? super T> q):创建一个引用给定对象的新的软引用,并向给定队列注册该引用。WeakReference(T referent):创建引用给定对象的新的弱引用,新的引用没有向任何队列注册。 WeakReference(T referent, ReferenceQueue<? super T> q):创建引用给定对象的新的弱引用,并向给定队列注册该引用。get()方法。 PhantomReference(T referent, ReferenceQueue<? super T> q):创建一个引用给定对象的新的虚引用,并向给定队列注册它。上面这三种引用类型,都有向给定的队列注册该引用的构造器。什么是引用队列呢,它是用作“回收前清理工作”的工具。而PhantomReference虚引用只能依赖于引用队列。
import java.lang.ref.PhantomReference;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.ref.SoftReference;import java.lang.ref.WeakReference;class Demo {String name;public Demo(String name) {this.name = name;}@Overridepublic String toString() {return name;}}public class Rerence {public static void main(String[] args) throws InterruptedException {// 创建一个引用队列ReferenceQueue<Demo> rq = new ReferenceQueue<Demo>();// 创建一个软引用SoftReference<Demo> srf = new SoftReference<Demo>(new Demo("Soft Demo"), rq);// 创建一个弱引用WeakReference<Demo> wrf = new WeakReference<Demo>(new Demo("Weak Demo"), rq);// 创建一个虚引用PhantomReference<Demo> prf = new PhantomReference<Demo>(new Demo("Phantom Demo"), rq);// TestRef(srf, rq); // 1// TestRef(wrf, rq); // 2// TestRef(prf, rq); // 3}// 用于测试引用public static <T,F extends Reference<T>> void TestRef(F ref, ReferenceQueue<T> rq) throws InterruptedException {System.out.println(ref.getClass().getSimpleName()+" get : "+ref.get());Thread.sleep(100);if (ref.get() != null) {// 判断垃圾回收器是否回收了对象if (ref.isEnqueued())System.out.println("引用所指向的对象被回收!");elseSystem.out.println("引用所指向的对象存在!");System.out.println("启动垃圾回收器,并使主线程睡眠。");System.gc();// 使主线程睡眠,让执行权给垃圾回收器Thread.sleep(100);// 再次判断垃圾回收器是否回收了对象if (ref.isEnqueued()){System.out.print("引用所指向的对象被回收,");}else{System.out.print("引用所指向的对象仍然存在,");}// 用于返回队列中的引用Reference<? extends T> r = rq.poll();if(r!=null && r==ref){System.out.println("引用队列中有引用,此引用指向的对象:"+r.get());}else{System.out.println("引用队列中没有引用。");}}else{System.out.println("该引用并没有指向对象!");}}} /* Output:// 如果开启1,屏蔽2和3:SoftReference get : Soft Demo引用所指向的对象存在!启动垃圾回收器,并使主线程睡眠。引用所指向的对象仍然存在,引用队列中没有引用。// 如果开启2,屏蔽1和3:WeakReference get : Weak Demo引用所指向的对象存在!启动垃圾回收器,并使主线程睡眠。引用所指向的对象被回收,引用队列中有引用,此引用指向的对象:null// 如果开启3,屏蔽1和2:PhantomReference get : null该引用并没有指向对象!*///:~
虚引用基本是形同虚设,它引用的对象随时会被垃圾回收器回收;具有弱引用的对象拥有的稍微长一点的生命周期,但垃圾回收器执行回操作时,依然有可能回被垃圾回收器回收;生命周期长的还是软引用,但在虚拟机内存不足的情况下依然会被回收。所以可出这些引用的方式真的不适合在线上使用,否则在极度容易出现鼓掌而在排查时很难检测出结果。