封闭对象的引用通过匿名类java进行转义

时间:2011-02-26 20:38:23

标签: java concurrency reference this anonymous-class

我正在实践中阅读Java并发性,以下示例来自于此。我的问题是 这个参考逃脱是什么意思?会有什么问题? 。该引用如何从doSomething(e)中逃脱。

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            }
        );
    }
}

这如何解决问题

public class SafeListener {
    private final EventListener listener;
    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        };
    }
    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

修改:

我试过以下的例子

public class Escape {
    public  Escape( Printer printer ){
        printer.print(new Escaper(){
            @Override
            public void parentData(){
            theCulprit1(Escape.this);
            }
            public String name = "shal";
            @Override
            public void theCulprit(){
            System.out.println( this.name );
            System.out.println( Escape.this.age );
            }
        });
        canAccess();
    }
    public void  canAccess(){
    this.age = "25";
    }
    public String age = "62";
    @SuppressWarnings("unused")
    public static void main(String args[]){
    Escape escape = new Escape(new Printer());
    }
}

class Printer{
    public void print(Escaper escaper){
    escaper.theCulprit();
    escaper.parentData();
    }
}

class Escaper{
    public void parentData(){
    }
    public void theCulprit(){
    }
    public void theCulprit1(Escape escape){
    System.out.println(escape.age);
    }
}

由于逃生物体的构造不完整 这输出shal 62 62

我在哪里改变了我的代码

public class Escape {
    private final Escaper escaper;
    private Escape( ){
        escaper = new Escaper(){
            @Override
            public void parentData(){
            theCulprit1(Escape.this);
            }
            public String name = "shal";
            public void theCulprit(){
            System.out.println( name );
            System.out.println( age );
            }
        };
        canAccess();
    }
    public void  canAccess(){
    age = "25";
    }
    public String age = "62";
    public static Escape newInstance( Printer printer){
    Escape escape = new Escape();
    printer.print(escape.escaper);
    return escape;
    }
    @SuppressWarnings("unused")
    public static void main(String args[]){
    Escape.newInstance(new Printer());
    }
}

在这里。输出shal 25 25

我是对的吗? 还有任何重新排序的操作,因为在第一个例子中,年龄被初始化为62。 即使没有在我的第二个例子中使escaper领域最终确定它也有效!

2 个答案:

答案 0 :(得分:8)

在第一种形式中,事件侦听器对象被注册到构造函数中的事件源,因此它使自己(以及通过关联“this”对象)可用于事件源之前构造函数完成。如果内部类对象转义,外部对象也会转义。

为什么这是一个问题?注册事件侦听器后,事件源可以随时调用其方法。想象一下,事件源正在使用的线程开始调用事件侦听器方法。现在甚至可以在构造函数完成之前发生这种情况。

由于可见性问题,此问题比看上去要糟糕。即使您将注册作为构造函数执行的“最后一次操作”,仍有可能看到部分构造对象或处于无效状态的对象。在订购之前没有适当的发生,根本没有可见性保证。

在订购之前声明它最终会发生 - 因此第二种形式。

答案 1 :(得分:2)

当你有一个非静态的内部类时,比如

class Outer {
    class Inner {
    }
}

内部类有一个引用外部类的隐藏字段,所以你可以想象它就像这个

class Outer {
    class Inner {
        Outer hiddenOuter;
    }
}

因此,无论使用内部对象,外部对象都是可引用的,因此它的生命周期至少与内部对象一样长。