zoukankan      html  css  js  c++  java
  • effective解读-第八条 避免使用finalizer和Cleaner

    java9之前finalizer,java9使用cleaner代替了finalizer。相比finalizer,cleaner(它存在于一个独立类Cleaner中,需要时候注入到对应类中即可)不会污染API而且cleaner有类库可以控制它的线程(它两都在后台线程中执行)。

    避免使用的原因:

    1. 行为的不稳定性

      • 它两都不能保证及时的执行,从方法可达到(对象被置空了)开始到最终的执行,时间是任意长的。所以千万不要使用他们来更新重要的持久状态,如释放流资源、分布式锁等。

      • System.gc和System.runFinalization这两个方法会增加finalizer和cleaner被执行的机会,但是不保证一定会执行。唯一能保证它两会被执行的两个方法(System.runFinalizersOnExit和Runtime.runFinalizersOnExit)有致命的缺陷,已经被废除很久了。

    1. 移植性问题

      不同的JVM堆垃圾回收的算法不同,如果程序依赖finalizer或者cleaner被执行的时间点,那么程序的表现可能截然不同

    2. 性能问题

      finalizer和cleaner有一个非常严重的性能损耗。

    3. 安全问题

      • finalizer中如果出现异常会导致线程终止,但是不会打印线程轨迹甚至警告都不会打印出来,而且使正在销毁的对象处于破坏状态,另一个线程如果使用这个破坏状态的对象会出现行为的不确定性。cleaner没有这个问题。

      • finalizer攻击:利于finalizer方法,构建出恶意子类对象,非法调用父类方法。final类不会被构建恶意子类,所以不会遭到finalizer攻击。对于非final类,重写一个空的finalizer方法并用final修饰来防止finalizer攻击。

        //构建对象使用后不能再次被实例化
        public class Demo{
            private boolean flag = true;
            //防止实例化
            public  Demo() {
                if (flag){
                    throw new RuntimeException("不准许再次创建对象");
                }
            }
            public  void say() {
                System.out.println("DemoUtils.say");
            }
        }
        //构建非法子类
        class Demo2 extends Demo{
            public Demo2(){}
            //构建finalizer攻击
            @Override
            protected void finalize() throws Throwable {
                //会调用父类方法
                this.say();
                System.exit(0);
            }
            public static void main(String[] args) throws InterruptedException {
                try {
                    //创建子类对象必然会调用父类构造,所以会发生异常
                    //但是在gc中还是执行了父类的方法
                    Demo demo = new Demo2();
                    demo.say();
                } catch (Exception e) {
                    System.out.println(e);
                }
                System.gc();
                //给垃圾回收提供时间
                Thread.sleep(5000);
            }
        }
        //运行结果
        java.lang.RuntimeException: 不准许再次创建对象
        DemoUtils.say

    两个用处:

    1. 安全网

      当资源的所有者忘记使用close方法的时候,finalizer和cleaner可以充当安全网,虽然不能保证及时的释放资源,但是迟一点释放总比永远不释放要好。要使用这样的安全网就要认证的考虑清除是否值得付出这样的代价。所以Java一些AutoCloseable实现中都添加了安全网。

      这是FileOutputStream的源码

    2. 回收本地对等体对象

      本地对等体:java操作native方法其实是委托给一个本地对等体对象,使用完成后java对象会被GC回收,但是这个对等体对象不是java对象不会被会GC回收。如果这个对象性能可以接受,而且没有需要及时释放的资源那么就可以使用finalizer或者cleaner进行回收了。但是如果这个对等体性能无法接受且拥有必须被及时终止的资源,那么就需要提供一个close方法了。

    作者:刘志红

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

  • 相关阅读:
    二叉树前序中序遍历求后序遍历
    二叉树的遍历
    Codeforces Round #381 (Div. 2)
    Codeforces Round #380 (Div. 2, Rated, Based on Technocup 2017
    Codeforces Round #379 (Div. 2)
    HDU 2896 ac自动机裸题
    RabbitMQ镜像模式双节点部署时故障转移过程中队列中消息的状态
    Maven搭建Spring MVC时使用jstl无效
    在使用HttpClient做客户端调用一个API时 模拟并发调用时发生“死锁"?
    使用mongodb提供的dotnet core sdk进行地理位置运算
  • 原文地址:https://www.cnblogs.com/chengxuyuan-liu/p/14591193.html
Copyright © 2011-2022 走看看