what is this escape?
在《Java Concurrency in Practice》一书的第三章提到了对象的发布与逃逸。作者举了this指针逃逸的例子。所谓的“this逃逸”,指的是在构造函数返回之前,其他线程就已经取得了该对象的引用。此时,对象尚未完成实例化,还是残缺的,取得对象引用的线程使用残缺的对象可能引发令人遗憾的错误。作者举的例子,不太容易理解,下面对该例子做适当扩展来理解“this逃逸”。
show me the code
我在com.gongjun.study.concurrency包下建了下面的三个类:
public class ThisEscape {
private final int num;
public ThisEscape(EventSource source) {
source.registerListener(new EventListener() {
public void onEvent(Object o) {
doSomething(o);
}
});
num = 42;
}
private void doSomething(Object o) {
if (num != 42) {
System.out.println("Race condition detected at " + new Date());
}
}
}
public class EventSource {
public void registerListener(EventListener listener) {}
}
public interface EventListener {
public void onEvent(Object o);
}
analysis the code
1.手动编译源代码,生成class文件
javac EventSource.java EventListener.java ThisEscape.java
我们看到对ThisEscape中的内部匿名类EventListener生成了对应的class文件ThisEscape$1.class
2.查看ThisEscape的字节码
javap -verbose ThisEscape.class
在ThisEscape的构造器中,new了一个匿名类ThisEscape$1,并将自己作为入参,即为我们所说的this引用。
3.查看匿名类ThisEscape$1的字节码
javap -verbose ThisEscape\$1.class
从字节码中,我们看到匿名类确实持有了外部类的引用。
由此,我们可以看出确实发生了对象(this)的逃逸,EventSource中的registerListener完全有可能在异步线程中执行,某种情况下ThisEscape还没完全构造完全,而在EventListener的匿名类中通过持有this引用,调用ThisEscape的doSomething方法,会出现不满足预期的结果。