【JAVA Reference】Finalizer 剖析 (六)

我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码


一、前言

建议提前阅读:

  1. 【JAVA Reference】ReferenceQueue 与 Reference 源码剖析(二)
  2. 【JAVA Reference】Cleaner 源码剖析(三)
  3. 【JAVA Reference】Cleaner 对比 finalize 对比 AutoCloseable(四)

二、架构

2.1 代码架构

在这里插入图片描述
在这里插入图片描述

  • Finalizer 继承 FinalReference 再继承 Reference。
2.2 UML流程图

在这里插入图片描述

=== 点击查看top目录 ===

三、思考 Finalizer Vs Cleaner 放一起

3.1 代码 demo
public class _05_03_TestCleanerWithFinalize {
     
    public static void main(String[] args) throws Exception {
     
        int index = 0;
        while (true) {
     
            Thread.sleep(1000);
            // 提醒 GC 去进行垃圾收集了
            System.gc();

            // 该对象不断重新指向其他地方,那么原先指针指向的对象的就属于需要回收的数据
            DemoObject obj = new DemoObject("demo" + index++);
            Cleaner.create(obj, new CleanerTask("thread_" + index++));
        }
    }

    @Data
    @AllArgsConstructor
    @ToString
    static class DemoObject {
     
        private String name;

        @Override
        protected void finalize() throws Throwable {
     
            System.out.println("finalize running DoSomething ..." + name);
        }
    }

    static class CleanerTask implements Runnable {
     
        private String name;

        public CleanerTask(String name) {
     
            this.name = name;
        }

        // do something before gc
        @Override
        public void run() {
     
            System.out.println("CleanerTask running DoSomething ..." + name );
        }
    }
}

输出:

finalize running DoSomething ...demo0
CleanerTask running DoSomething ...thread_1
finalize running DoSomething ...demo2
CleanerTask running DoSomething ...thread_3
finalize running DoSomething ...demo4
CleanerTask running DoSomething ...thread_5
finalize running DoSomething ...demo6
CleanerTask running DoSomething ...thread_7
finalize running DoSomething ...demo8
...

可以看到,每次 finalize 总是比 Cleaner 先执行,不管你run几次,结果都一样,那么思考一下为什么?

=== 点击查看top目录 ===

3.2 为什么 finalize 总是比 Cleaner 先执行 ?
  • 结论先抛出来: Cleaner 和 finalize 内部都有指针Pointer 指向了即将要回收的 Object 对象,但是 Cleaner 底层是虚引用(PhamtonReference),而 finalize的底层是 Finalizer ,属于强引用。所以,必须强引用的释放完对象,才轮到 Cleaner。

=== 点击查看top目录 ===

四、Finalizer 源码剖析

4.1 父类 FinalReference
class FinalReference<T> extends Reference<T> {
     
    public FinalReference(T referent, ReferenceQueue<? super T> q) {
     
        super(referent, q);
    }
}
  • 注意:这个类的修饰符是 default ,也就是只能在包 java.lang.ref 内被使用 。
  • 由继承关系可以得知,FinalReference 只有一个子类 Finalizer
    在这里插入图片描述

=== 点击查看top目录 ===

4.2 Finalizer 类
final class Finalizer extends FinalReference<Object> 
  • 注意,Finalizer 是个 final 类,也就是断子绝孙类,不会有继承,可以防止篡改与注入。
  • Finalizer 类的修饰符是 default ,也就是只能在包 java.lang.ref 内被使用 。那么总览了一下,他是 JVM 调用的。
4.3 Finalizer 类变量
4.3.1 私有static变量 queue

Finalizer引用的对象被gc之前,jvm会把相应的Finalizer对象放入队列 queue

    private static ReferenceQueue<Object> queue = new ReferenceQueue<>();

=== 关于Reference的四个状态,可以看图 ===
=== 点击查看top目录 ===

4.3.2 私有static变量 unfinalized

静态的Finalizer对象链,每=== 实例化 ===一个对象,这个队列就会插入=== add ===一个。

    // 静态的Finalizer对象链
    private static Finalizer unfinalized = null;

=== 点击查看top目录 ===

4.3.3 next + prev 指针
    // 双端指针
    private Finalizer
        next = null,
        prev = null;

=== 点击查看top目录 ===

4.3.3 私有 static final 变量 lock
    private static final Object lock =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值