JAVA虚引用介绍

虚引用

虚引用需要java.lang.ref.PhantomReference类来实现,虚引用顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会觉定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。
虚引用的主要作用是跟踪对象被垃圾回收的状态,仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。PhantomRefernce的get方法总是返回null,因此无法访问对应的引用对象,其意义在于说明一个对象已经进入finalization阶段,可以被gc回收,用来实现比finalization机制更灵活的回收操作。换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步处理。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
其实通俗点就是,一个死刑犯,缓期3天执行,那么这个死刑犯需要关押在指定监狱(ReferenceQueue)等待执行,因为有3天缓期,在这3天内需要死刑犯处理后事。这就是回收前需要被队列保存
下面在实现虚引用需要介绍下ReferenceQueue引用队列,回收前需要被引用队列保存下。
结构如图:
引用队列是为了配合SoftReference、WeakReference、PhantomReference使用,它们三个在GC回收之前会被放到引用队列里ReferenceQueue.保存下。
在这里插入图片描述
下面我们用代码来证实下


import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class ReferenceQueueDemo {
    public static void main(String[] args) {
        Object o1 = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        WeakReference<Object> weakReference = new WeakReference<>(o1,referenceQueue);
        System.out.println("***************GC回收前***************");
        System.out.println(o1);
        System.out.println(weakReference.get());
        System.out.println(referenceQueue.poll());

        System.out.println("***************启动GC***************");
        o1 = null;
        System.gc();
        try {
            Thread.sleep(500); //确保GC都执行完了
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(o1);
        System.out.println(weakReference.get());
        System.out.println(referenceQueue.poll());

    }
}

运行如下:
在这里插入图片描述

虚引用代码演示


import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceDemo {
    public static void main(String[] args) {
        Object o1 = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> phantomReference = new PhantomReference<>(o1,referenceQueue);
        System.out.println("***************GC回收前***************");
        System.out.println(o1);
        System.out.println(phantomReference.get());
        System.out.println(referenceQueue.poll());

        System.out.println("***************启动GC***************");
        o1 = null;
        System.gc();
        try {
            Thread.sleep(500); //确保GC都执行完了
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(o1);
        System.out.println(phantomReference.get());
        System.out.println(referenceQueue.poll());
    }
}

运行结果:
在这里插入图片描述
说明下:
java提供了4种引用类型,在垃圾回收的时候,都有自己各自的特点。ReferenceQueue是用来配合引用工作的,没有ReferenceQueue一样可以运行。
创建引用时候可以指定关联的队列,当GC释放对象内存的时候,会将引用加入到引用队列,如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象内存被回收之前采取必要行动这相当于是一种通知机制。
当关联的引用队列中有数据的时候,意味着引用指向的堆内存中的对象被回收。通过这种方式,JVM允许我们在对象被销毁后,做一些我们自己想做的事情。


版权声明:本文为baidu_37313657原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。