关于”隐式允许this引用逸出“

在《Java Concurrency in Practice》中,对于发布对象和数据逸出有两种示例,
其中之一是:
Listing 3.6. Allowing Internal Mutable State to Escape. Don't Do this.

class UnsafeStates {
private String[] states = new String[] {
"AK", "AL" ...
};
public String[] getStates() { return states; }
}


这个好理解;

另外一个示例是:
Listing 3.7. Implicitly Allowing the this Reference to Escape. Don't Do this.

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

作者认为“it implicitly publishes the enclosing ThisEscape instance as well, because inner class instances contain a hidden reference to the enclosing instance.”

作者的改进建议是:

If you are tempted to register an event listener or start a thread from a constructor, you can avoid the improper construction by using a private constructor and a public factory method, as shown in SafeListener in Listing 3.8.

Listing 3.8. Using a Factory Method to Prevent the this Reference from Escaping During Construction.
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;
}

}



作者对于错误的原因是这样解释的:
ThisEscape illustrates an important special case of escapewhen the this references escapes during construction. When the inner EventListener instance is published, so is the enclosing ThisEscape instance. But an object is in a predictable, consistent state only after its constructor returns, so publishing an object from within its constructor can publish an incompletely constructed object. This is true even if the publication is the last statement in the constructor. If the this reference escapes during construction, the object is considered not properly constructed.
有谁能把这个原因解释清楚点,即:为什么说这是一个未完成的对象呢,一旦内部匿名类那段代码执行完后,对象不就被注册了么?

4个回答

首先,在之前我并不知道或已对this引用逸出这回事没有够印象。
在看查看资料后,说说个人的理解,如理解有误还请见谅。

对this逸出代码作部分修改,易于理解。
原文:
[code="java"]
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}[/code]

修改后。

[code="java"]
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
a
....b;
....c;
....d;
}
}[/code]

在构造ThisEscape对象时,代码执行到a处时对事件的注册已经完成,而此时构造函数并没有完成。
如正是这个时刻,事件发生,那么在doSomething中this是可见的。
那么就出现了this逸出的问题。

再次声明,本人也不知道理解是否正确。仅做参考。

楼上正解~
未完成的对象是指ThisEscape而不是EventListener。

主要是doSomething方法中可以使用this(但是ThisEscape没完成实例化),使用一个半成品的对像,肯定会出现与预期不一致的结果。

因为只有当构造函数返回时对象才处于可预测和一致的状态,当从构造函数发布对象时,只是发布类一个尚未完成的对象,哪怕发布对象的语句位于最后一行。虽然EventListener放在最后一行,使用到ThisEscape的字段,但是此时字段可能还没执行完成赋值

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐