通过匿名类java引用包围对象转义 [英] Reference of enclosing object escape through anonymous class- java

查看:127
本文介绍了通过匿名类java引用包围对象转义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在实践中阅读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;
}
}

编辑 p>

我试过下面的例子

  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
}
}

类打印机{
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字段final。

解决方案

在第一种形式中,事件监听器对象被注册到构造函数 中的事件源< (并通过关联this对象)在构造函数完成之前可用于事件源。如果内部类对象转义,外部对象也是如此。



为什么这是一个问题?一旦事件监听器被注册,事件源可以在任何时候调用它的方法。想象一下,事件源正在使用的线程开始调用事件侦听器方法。



但是,由于可见性问题,这个问题比看起来糟糕。使注册是构造函数所做的最后一个操作,仍然有可能看到部分构造的对象或处于无效状态的对象。在没有正确发生的情况下,在排序之前没有可见性保证。



声明它的最终提供了发生之前排序(因此第二种形式)。


I am reading Java concurrency in practice and the below examples are from that. And my questions are What do they mean by this reference escape?. What will be the problem? . How does the this reference escapes from doSomething(e).

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

How does this solves the problem

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;
    }
}

Edit :

I have tried the below examples

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);
    }
}

Due to incomplete construction of the escape object This outputs shal 62 62

Where as i changed my code like this

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());
    }
}

Where as here.It outputs shal 25 25

Am i right ? Also is there any re-ordering of operations, because in the first example the age got initialized to 62. Even without making the escaper field final in my second example it works !

解决方案

In the first form, the event listener object gets registered to the event source within the constructor, and thus it makes itself (and by association the "this" object) available to the event source before the constructor completes. If the inner class object escapes, so does the outer object.

Why is this a problem? Once the event listener is registered, the event source may invoke its methods at any time. Imagine a thread that the event source is using starts invoking the event listener methods. This now can happen even before the constructor completes.

This problem is worse than it appears, however, due to visibility issues. Even if you make the registration the "last operation" that the constructor does, there is still the possibility of seeing partially constructed object or an object in an invalid state. There is simply no visibility guarantee in the absence of a proper happens-before ordering.

Declaring it final affords that happens-before ordering (thus the second form).

这篇关于通过匿名类java引用包围对象转义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆