对象发布与逃逸-this逃逸
2017-09-16 本文已影响274人
兰塔项
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
![](https://img.haomeiwen.com/i6724284/048da6fc4bba71bb.png)
我们看到对ThisEscape中的内部匿名类EventListener生成了对应的class文件ThisEscape$1.class
2.查看ThisEscape的字节码
javap -verbose ThisEscape.class
![](https://img.haomeiwen.com/i6724284/b5ce107bac3f6791.png)
在ThisEscape的构造器中,new了一个匿名类ThisEscape$1,并将自己作为入参,即为我们所说的this引用。
3.查看匿名类ThisEscape$1的字节码
javap -verbose ThisEscape\$1.class
![](https://img.haomeiwen.com/i6724284/e90b4f3a3f8d3141.png)
从字节码中,我们看到匿名类确实持有了外部类的引用。
由此,我们可以看出确实发生了对象(this)的逃逸,EventSource中的registerListener完全有可能在异步线程中执行,某种情况下ThisEscape还没完全构造完全,而在EventListener的匿名类中通过持有this引用,调用ThisEscape的doSomething方法,会出现不满足预期的结果。