this逃逸就是说,在构造函数返回之前,其他线程就已经取得了该对象的引用,由于构造函数还没有完成,所以,对象也可能是残缺的,所以,取得对象引用的线程使用残缺的对象极有可能发生错误的情况,因为这两个线程是异步的,取得对象引用的线程并不一定会等待构造对象的线程完结后在使用引用。
this逃逸经常发生在构造器中启动新线程的时候,如:
public class ThreadThisEscape {
public ThisEscape() {
new Thread(new EscapeRunnable()).start();
// ...
}
private class EscapeRunnable implements Runnable {
@Override
public void run() {
// ThreadThisEscape.this就可以引用外围类对象, 但是此时外围类对象可能还没有构造完成, 即发生了外围类的this引用的逃逸
}
}
}
下面的情况也可能发现this引用逃逸:
public class FinalExample{
final int i;
static FinalExample obj;
public FinalExample(){
i=1;//(1)
obj=this;//(2)
//(1),(2)可能被重排序
}
//线程1
public static void writer(){
new FinalExample();
}
//线程2
public static void reader(){
if(obj !=null){
int temp =obj.i;
}
}
}
由于(1),(2)可能被重排序,当线程1开始执行,被构造的对象的引用会在构造函数内溢出,然后线程2开始执行就访问到了还未赋值的final 变量 i, 最后线程1才在构造函数内部给 i 赋值。这就错误的查看了。
因此必须强调,final关键字的可见性是指: 被final修饰的字段在构造前中一旦初始化完成,并且构造器没有把“this”的引用传递出去(this引用逃逸是一件很危险的事情,其他线程有可能通过这个引用访问到“初始化了一半”的对象),那在其他线程中就能看见final字段的值。