00:00
好,那接下来啊,咱们来给大家讲,这个叫虚引用,前面呢,咱们已经讲了,叫强软弱对吧?哎,加上这个虚用呢,一共就是我们要讲的这个四种引用类型,当然最后呢,咱们还有一个呢,叫做中结器引用,这个大家了解一下就行啊,那么这个虚引用这个微何物呢?诶,我们来看一下,那称为呢,叫phantom reference,它呢最简单的一个描述呢,叫做对象回收跟踪啊,就是这样最简洁的一句话来描述啊,咱们来理解,哎,我们来看一下说这个虚引用啊,咱们也可以称为呢,叫做幽灵引用,或者叫幻影引用,哎,或者叫幻象引用都行,是所有引用类型当中最弱的一个,就相较于我们说强软弱啊,然后他呢是排第四的是吧?呃,这个你看叫虚用啊,就虚到啥程度呢?你可以用咱们中国的一个成语叫做形同虚设是吧?啊,就约等于是形同虚设啊,咱们在实际开发当中,这个序用啊,用的也非常少啊,基本上大家就见不到啊,那你看我们下边的描述。说一个对象啊,是否有这个续用的存在呢,完全不会决定对象的生命周期啊,就已经弱到这种程度了,你看我们如果说是一个强引用的话呢,这个引用变量呢,它指向了一个new的对象啊,即使呢,你出现OM的话呢,我们这个指针如果存在,你也不能够去回收这个垃圾。
01:14
哎,当然这个软饮用弱引用呢,我们在相应的一个场景下呢,都能够去回收,但是在你回收之前的话呢,它还是有这个生命周期的,对吧?哎,当然对于我们这个续用来讲,它就非常的弱啊,它不决定对象的生命周期啊,那如果要是一个对象呢,只有这个续用呢,啊,那就跟没有引用呢,几乎是一模一样的啊,就弱到这种程度啊,那我们如果声明了一个这个续用的对象,那就比如我们下边这个跟咱们前面整个套路呢类似啊,通过这个phantom reference呢,我们用了一个对象,然后里边放的实体呢,就是这个对象,咱们把这个呢强引用呢,也给它这个取消是吧,那这时候呢,你就只有一个去引用,当我们啊,通过这个钙的方法去获取的时候呢,你发现根本也拿不到这个对象。诶根本也拿不到这个对象,在咱们前面讲的这个,呃,比如这个软引用的时候,呃,咱们是不是通过这个get的时候呢,能够拿到,就是一上来的时候呢,去获取都有是吧?然后这个弱引用的话也是一样,咱们一上来的时候呢,就试图去获取都能够达到,而对于我们这个叫哎虚用来讲呢,你上来呢试图去获取的时候。
02:15
哎,就拿不到了。啊,就拿不到了啊,他根本呢也不决定对象的生命周期啊,那么我们设置这个续用目的是什么呀?诶咱们这块呢,其实也写了啊,唯一目的啊就是追踪啊垃圾的一个回收过程啊,比如说我们在这个对象呢,被回收的垃圾回收器回收的时候呢,我们收到一个系统的通知那一会儿呢,咱们这个代码呢,也是这样的一个意思啊。行,下面呢是一个描述,这个描述呢,主要就是针对于我们如何去实例化的一个场景啊,你看我这呢,就放了一个比较标准一个代码啊,看着稍微长一点哈,我们呢去new一个啊phantom reference就是一个虚引用,跟前面的套路一样,咱们需要把你这个对象呢造出来,我就放这儿了,然后把这个强引用呢,给它支成个not,当然需要注意的就是我们这个phantom reference啊,咱们看的这个类是吧,这个类的话呢,你ctrl o一下,它就只有这样的一个构造器,这个构造器呢,它除了放你这个核心的数据之外呢,必须要传一个啊,Reference q。
03:07
就我们这个引用队列。啊,一定要传一个应对列,这跟咱们前面讲的这个软云和弱云呢,是有比较大的一个区别的,你那这里边提到了,说在创建的时候呢,必须要提供一个哎软这个硬堆列呢,做一个参数啊为什么呀,因为呢,咱们垃圾回收器在回收这个对象的时候呢,一旦你回收了啊,发现你是个虚引用,咱们就把你这个呃引用的话呢,就放到这个应用队列里。哎,放向形队列的,放向形队列的话呢,我们可以去处理一个引形队列,然后呢,去获取一个通知,哎,获取个通知啊,就这个意思。嗯,这呢是我们说由于啊续引用可以跟踪对象的回收时间,因此呢也可以将一些资源释放呢,哎,就放置在这个虚引用当中进行记录和执行啊,就是回收这个垃圾的时候呢,我们会有个通知嘛,诶所以呢,你可以做这样的一个处理行,那这呢是我们关于这个代码的一个说明,诶关于这个文档的一个说明,下面呢,咱们还是给大家举一个这个代码的例子啊,那这个例子呢,我写起来呢,就会稍微的麻烦一点。
04:03
啊就会麻烦一点,咱们呢带着大家呢来做一个剖析啊,其实主要呢,就是我们这个类呢,你看有有点长是吧?啊实际上这个这个引用的话呢,它就本身就比较长啊行啊一剖析的大家就清楚了啊看一下咱们当前这个类啊,上来的话呢,我们是声明这个当前这个类的一个对象啊static的啊只是一个声明,然后呢,我们又声明了一个叫影形队列啊这呢都没有实例化啊先都摆到这儿,然后呢,这个现场咱们先不管它,我把它收起来啊下面呢,有个final的这个方法咱们知道呢,在进行垃圾回收的时候呢,我们要回收这个对象了,呃,首次呢要诶就是你要之前没有调用过这个finalize,它系统呢会主动调用这个finalize方法,对吧?我在那写了一个这样一句话,然后呢,我们这有一个这样的操作,这个咱们知道呢,是不是会使得当前这个对象呢复活呀,哎,咱们讲前面那个finalization机制的时候说到过这个问题,对吧?哎,这就是可复活的啊呃,然后下面呢,是咱们这个酶方法。这个酶方法呢,一开始的时候,这个是我们涉及到这个线程的问题,咱们呢,也暂时呢先忽略掉啊,我就先比如说先注释掉了啊,咱们先来看这个核心的操作,在酶方法里边呢,我们把当前的这个队列呢给它呃实例化了,把我们当前这个类的对象呢实例化了,下边呢,我们就造一个叫phantom reference这样的一个呃虚引的一个这个这个对象是吧,然后呢,拟完以后把我们这个呃实体的这个对象呢,我们放到这里边,然后把你这个引用对象,呃队列呢也放到这里边啊这张就都妥了啊放进去了,那放进去以后呢,我们首先呢,试图拿着这个虚引用,那我们去get一下。
05:34
啊,试图我们去get一下是吧,哎,下边这个操作呢,咱们也暂时的全都给他,嗯,我从这到这是吧。咱们呢,也全都给他呢,做一个注释,诶,我们先试图的去获取一下,说这里边这个,呃,你用的这个对象能不能拿到啊。啊,这个说我们这个程序当中没有出现对应的这个异常了是吧?哎,我们这个就白写了哈,哎把它呢,嗯。这个要注释的话呢,咱们需要把这个TRY呢,也得注释一下是吧,稍微麻烦一些啊。
06:03
诶把这也注释一下行,那这时候呢,咱们就是一个盖的操作啊,就是一个盖操作跑一下。那你看这时候是个闹,呃,也就是说呢,呃,对于我们这个叙用来讲啊,它不同于前面的软引用和弱引用,你试图呢,拿它这里边的对象的话呢,是拿不到的,嗯,是拿不到的,哎就是这样一个问题,行这呢就先说清楚这个事儿,然后咱们把这个呃柱子的信息呢,咱们再给它打开啊,那么接下来的话呢,我们把这个强引用呢,给它去掉了。哎,把这个强引用,这不是你有个强引用嘛,去掉了,那就意味着我们现在只有这个去引用了啊,只有这个去引用,然后呢,我们进行GC。啊,我们进行这些,你想想它比这个,呃,我们说的这个weak reference啊,把这个比这个弱引用呢,还要弱一些啊,那就意味着我们这个GC的时候,大家想我们是不是就要回收你new的当前这个类的对象了,哎,就我们这个obg是吧,哎就要回收它了,那回收的话呢,我们呃就会自动的去调这个finalize这个方法,但是你一调这个finalize这个方法的话呢,咱们在这个方法当中又把自己给复活了。
07:09
诶所以啊,其实这块呢,是咱们讲的这个旧知识的啊,诶我这块呢,EGC啊,为了保证咱们这个GC操作呢,一定能执行,我这块让他停了这个一秒钟啊,因为它不是有一个不确定性嘛,是吧?哎停了一秒钟之后呢,保证你那个泛类方法呢被调过,这时我们在判断的时候,实际上它还是一个可用的,因为咱们给复活了是吧?诶那暂时呢,我把这段代码呢先注释一下。来,我先注释一下,跑一下。嗯,行,看看大家能理解啊,现在获取不到,然后第二列ize,然后呢,因为你在这个finalize方法中把自己复活了,所以它仍然是一个可用的,行不多说啊,然后接下来呢,咱们进行这个第二次的一个GC。那第二次JC的话呢,我们把这个OB呢,也再制成个now,我在JC,因为咱们前面说过啊,Finalize方法呢,是不是只能够被调用一次啊。
08:01
哎,在这我们再写一下啊,发SH的方法啊,只能被啊调用啊一次,那这一次呢,就是咱们在第一次进行这个GC的时候呢,进行个调用,所以这时候你再去调的话呢,这就不好使了,这个时候你OB接它是不是就一定是一个闹了。对吧,哎,它就一定是个闹了,好,我们这时候呢,把它抛起来。嗯,没问题是吧,这是我们第一次的时候呢,你调理方法了,它还可用第二次呢,在这次的时候呢,就不掉了,然后呢,它就是个闹了。没问题是吧,哎,那这块好像跟我们讲的这个呃,虚用还没什么关系啊,下边呢,咱们要说这个关系了,诶我们在第二次JC的时候呢,咱们是不是真正的把这个对象呢,确实给回收掉了呀。哎,确实给回收掉了,因为第一次你看还能用,第二次是真用不了了,哎,他就是个no,是不是在这已经看到了是吧?行,那这时候呢,你真正给回收了,那我现在呢,造了一个这个这个县城。把这个线程呢,咱们打开啊,把这个线程打开,就是当我们看这啊,当我们发现呢,你要垃圾回收器回收的这个对象呢,是一个虚引用的时候呢,我们就会在回收对象以后,把这个虚引用呢,放到这个引用队列里边了。
09:13
哎,那咱们当前呢,要回收的这个对象呢,是不是就是这个obj呀。诶,你看我们这块呢,这不主要回收就是它是吧,那当你真正要调用这个GC操作呢,把它回收的时候,咱们就会呃,在你创建这个呃虚引用的这个位置上呢,把这个obj对象呢,就放到我们这个应对列里了。啊,咱们这个,呃,分线程呢,就是来操作这个影队列的。啊,操作运行队列的啊,咱们为什么一开始的时候呢,我就把它给打开了呢,实际上咱们一开始开的时候呢,这个分线程呢,看似呢,是不是就先于我们下边这个执行了,对吧?哟,往上调一下啊,就先于我们下边这个代码执行,当然我们上边这个star的时候呢,执行这个run方法,呃,因为呢,我们一开始的这个赢对称呢,它就是个no,所以一开始的时候呢,实际上都可以列解成是一个空转是吧?哎,在空转没什么意义啊啊一直在这块执行,也进步到我们这个依附结构当中,诶,当我们下边的这个GC操作一执行的时候。
10:11
哎,我们把这个obj对象呢,就给回回收掉了啊,因为判断不是no了吗,那一回收我们说哎就会将啊说一旦啊。哎,将这个OB对象。哎,回收哎就会呢,呃将此,哎需引用。哎,需引用,哎是不是哎存放到。哎,这个应用队列中啊。对吧?哎,就这个意思,也就是说当我们执行完这个操作以后呢,咱们在这个引用队列里边呢,就会存在着咱们说的那个虚用了,那当我们这块呢,在V1处回来啊,这个再去过来的时候呢,我们这里边就不是no了,那不是闹的情况下呢,我们通过这个应对列呢,做一个remove操作,实际上呢,就取出来你最近的那个去引用了,哎,我们就把它给取出来了,对吧,那取出来以后呢,我们看一下说你是不是闹呢,不是闹诶就是相当于我们确实能取出来东西嘛,哎,这呢也确实不是闹,因为你取出来了,所以呢,我们这块呢,就说可以追踪啊,这个垃圾回收的一个过程。
11:16
啊,我们说这个对象呢,哎,他被追随了,被销毁掉了。那就这个意思啊,行,那么这就我们这个操作,那这个操作里边呢,我先把这个给它注入掉啊,哎,就是我们造一个线程做一个start操作啊一执行。你看就这样子是吧,诶你看这块呢,我们就诶追踪了一下,那这个操作呢,就是我们上边的这个方法呢,就被调用了啊就是这个意思,那这块为什么停不了呢?是因为咱们上边这个呃分线程的话呢,我这始终是一个VO处是吧?诶所以它就接受不了我这块呢加一个这个呃设置为守护线程,这个大家应该懂哈,呃,这个设置成守护线程,一个特点呢,就是当程序中。啊,没有啊,这个非守护线程时。
12:01
哎,也就是当我们这个程序当中,如果你要是只剩下这个守护线程了,这个线程也就结束了啊,或者换句话呢,程序中没有这个非守护线程市场,哎,这个守护线程也就结束,哎也就来执行结束啊,这个大家应该讲线程的时候呢,应该都比较清楚啊,那就好比是我们正常的这个程序呢执行,那后台呢,是不是有一个垃圾回收的线程啊,诶垃圾回收线程实际上就是守护线程,当我们这个主线程结束了,垃圾回收线程,哎自动的也就哎结束了。行,那么加上一个它的话呢,我们再去执行。那你看这时候呢,当我们这个程序呢,这样执行完以后,哎,它这个呢,也就结束了。OK行,那这儿呢,就是我们给大家演示的这叫诶虚引用它的一个使用啊,比较典型的一个使用,通过这个例子呢,大家呢,再去体会一下关于我们这个叙用的一个介绍。行,那么至此的话呢,咱们把诶提到的这个强软弱虚啊这四种引用呢,咱们就讲清楚了,那么针对这道面试题也好,还是说针对于我们这个诶深入的去理解这个引用的细节也好啊这个大家呢自己呢再去总结总结,那么这个面试题的话呢,实际上呢,你可以结合着代码呢,我们去谈一谈,哎可以呢,去说的比较清楚一些啊,就是你单纯的说这个文字的话呢,还不行是吧?哎这个你真正的把这个代码呢,自己去写一写,体会体会,这个呢,你怎么表述呢它,哎都是有道理的,对吧?哎都是说不错的。
13:25
好,这呢,我们就说到这儿。
我来说两句