Java基础教程之this引用逃逸(2)

(2)在构造器中内部类使用外部类情况:内部类访问外部类是没有任何条件的,也不要任何代价,也就造成了当外部类还未初始化完成的时候,内部类就尝试获取为初始化完成的变量
•在构造器中启动线程:启动的线程任务是内部类,在内部类中xxx.this访问了外部类实例,就会发生访问到还未初始化完成的变量
•在构造器中注册事件,这是因为在构造器中监听事件是有回调函数(可能访问了操作了实例变量),而事件监听一般都是异步的。在还未初始化完成之前就可能发生回调访问了未初始化的变量。

在构造器中启动线程代码实现:

/**
 * 模拟this逃逸2:构造器中启动线程
 * @author Lijian
 *
 */
public class ThisEscape2 {
    final int i;
    int j;
    public ThisEscape2() {
        i = 1;
        j = 1;
        new Thread(new RunablTest()).start();
    }
    //内部类实现Runnable:引用外部类
    private class RunablTest implements Runnable{
        @Override
        public void run() {
            try {
                System.out.println(ThisEscape2.this.j);
            } catch (NullPointerException e) {
                System.out.println("发生空指针错误:普通变量j未被初始化");
            }
            try {
                System.out.println(ThisEscape2.this.i);
            } catch (NullPointerException e) {
                System.out.println("发生空指针错误:final变量i未被初始化");
            }
        }
       
    }
    public static void main(String[] args) {
        new ThisEscape2();
    }
}

构造器中注册事件,引用网上的一段伪代码将以解释:

public class ThisEscape3 {
    private final int var;
 
    public ThisEscape3(EventSource source) {
     //注册事件,会一直监听,当发生事件e时,会执行回调函数doSomething
        source.registerListener(
       //匿名内部类实现
            new EventListener() {
                public void onEvent(Event e) {
            //此时ThisEscape3可能还未初始化完成,var可能还未被赋值,自然就发生严重错误
                    doSomething(e);
                }
            }
        );
        var = 10;
    }
    // 在回调函数中访问变量
    int doSomething(Event e) {
        return var;
    }
}

3、怎样避免This逃逸?

  (1)单独编写一个启动线程的方法,不要在构造器中启动线程,尝试在外部启动。

...
private Thread t;
public ThisEscape2() {
    t = new Thread(new EscapeRunnable());
}

public void initStart() {
    t.start();
}
...

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b0df48a1fc9d98504aa9a19fca089100.html