• 《TIJ4》多态 E13 继承与清理中的引用计数问题


    引言

    通常,我们无需考虑对象的清理问题,垃圾回收器会代劳。然而在特定情况下,需要手动控制对象的清理,这时,我们必须小心翼翼为类创建dispose()方法。由于继承的原因,如果子类中含有自己特殊的清理,那么子类就必须重写dispose()方法,并在执行完自己特殊的清理后调用父类的dispose()方法,否则,基类就不会清理。

    一般的组合和继承中,对象会创建组合中的成员对象,并且在dispose()时释放这些对象。然而,如果这些成员对象中存在着被其他一个或多个对象所共享时,问题就复杂了,这时你不能简单得直接dispose(),你要考虑这些成员对象此时没有被其他对象共享,才能释放。下面是相关的代码:

    package polymorphism;
    
    class Shared {
        private int refcount = 0;
        private static long counter = 0;
        private final long id = counter++;
    
        public Shared() {
            System.out.println("Creating " + this);
        }
    
        public void addRef() {
            refcount++;
        }
    
        protected void dispose() {
            if (--refcount == 0) {
                System.out.println("Disposing " + this);
            }
        }
    
        @Override
        public String toString() {
            return "Shared " + id;
        }
    }
    
    class Composing {
    
        private Shared shared;
        private static long counter = 0;
        private final long id = counter++;
    
        public Composing(Shared shared) {
            System.out.println("Creating " + this);
            this.shared = shared;
            this.shared.addRef(); //通过某个 Shared 对象 构造一个 Composing 对象时,那么该shared 引用数加1
        }
    
        protected void dispose() {
            System.out.println("disposing " + this);
            shared.dispose();
        }
    
        @Override
        public String toString() {
            return "Composing " + id;
        }
    }
    
    public class ReferenceCounting {
        //存在被共享的成员对象时,共享对象使用引用计数方式进行dispose
        public static void main(String[] args) {
            Shared shared = new Shared(); //一个Shared对象被5个Composing对象共享
            Composing[] composings = {new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared), new Composing(shared)};
            for (Composing c : composings) {
                c.dispose();
            }
        }
    }
    
    /*输出:
    Creating Shared 0
    Creating Composing 0
    Creating Composing 1
    Creating Composing 2
    Creating Composing 3
    Creating Composing 4
    disposing Composing 0
    disposing Composing 1
    disposing Composing 2
    disposing Composing 3
    disposing Composing 4
    Disposing Shared 0
    */
    

    注意,这里coutner是Shared的示例的数量,还可以为id提供数值,类型是long可以防止溢出,id是final的,因为我们不希望它的值在对象生命周期中被改变。
    在将一个Shared对象附着在Composing上时,一定要调用addRef()来增加引用数量。
    Shared对象在dispose()时将根据引用数量来决定是否清理。

    问题

    在Shared类中添加一个finalize()方法,用来校验终止条件。

    添加的finalize()方法如下:

    protected void finalize(){
        if(refcount != 0){
            System.out.println("Error: object is not properly cleaned-up!");
        }
    }
    

    很明显,终止条件就是refcount为0时。

    而在main()方法最后添加如下代码:

    new Composing(new Shared());
    System.gc();
    System.runFinalization();
    

    新添加的这个Composing()对象没有进行释放(dispose),因此这个Shared()对象在被清理时不满足终结条件“引用数为0”。

    注:不能这样声明:

    Composing c = new Composing(new Shared());
    

    或者

    Shared s = new Shared();
    new Composing(s);
    

    这两种方式Shared对象会有引用指向,不会被垃圾回收。

  • 相关阅读:
    Codeforces Round #494 (Div. 3) D. Coins and Queries (贪心,数学)
    Codeforces Round #645 (Div. 2) D. The Best Vacation (贪心,二分)
    Codeforces Round #481 (Div. 3) F. Mentors (模拟,排序)
    Codeforces Round #646 (Div. 2) B. Subsequence Hate (思维,前缀和)
    windows的类似shell 命令操作 风行天下
    Linux防火墙iptables的策略 风行天下
    HP服务器安装配置教程 风行天下
    zabbix 监控数据库 及 tcp连接数 风行天下
    Linux日志 风行天下
    CENTOS 挂载ntfs移动硬盘 风行天下
  • 原文地址:https://www.cnblogs.com/mrbourne/p/8806502.html
Copyright © 2020-2023  润新知