java并发编程实践学习(四)对象的发布和逸出之this逃逸

原文来源: https://blog.csdn.net/aitangyong/article/details/25122741
《java并发编程实践》的第三章,对象的发布和逸出,作者提到了2种常见的对象逸出情况:在构造函数中注册事件监听,在构造函数中启动新线程。示例代码如下:


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

public class ThreadThisEscape {  
    public ThisEscape() {  
        new Thread(new EscapeRunnable()).start();  
        // ...  
    }  
      
    private class EscapeRunnable implements Runnable {  
        @Override  
        public void run() {  
            // ThreadThisEscape.this就可以引用外围类对象, 但是此时外围类对象可能还没有构造完成, 即发生了外围类的this引用的逃逸  
        }  
    }  

这2种方式的共同点是:在构造函数中使用内部类,并且代码可能会出现并行。也就是说,当内部类代码执行的时候,外部类对象的创建过程很有可能还没结束,这个时候如果内部类访问外部类中的数据,很有可能得到还没有正确初始化的数据。


stackoverflow上http://stackoverflow.com/questions/3705425/java-reference-escape讨论了this逸出的问题。下面给出2个具体点的例子,更容易理解this逸出的问题。


public class ThisEscape {
    private final int var;
 
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            }
        );
 
        // more initialization
        // ...
 
        var = 10;
    }
 
    // result can be 0 or 10
    int doSomething(Event e) {
        return var;
    }
}
事件监听器一旦注册成功,就能够监听用户的操作,调用对应的回调函数。比如出发了e这个事件,会执行doSomething()回调函数。这个时候由于是异步的,ThisEscape对象的构造函数很有可能还没有执行完(没有给var赋值),此时doSomething中获取到的数据很有可能是0,这不符合预期。

public class ThreadThisEscape
{
    private int weight = 0;
 
    public ThreadThisEscape()
    {
        weight = 1;
        
        new Thread(new EscapeRunnable()).start();
 
        // 模拟构造函数耗时
        for (int i = 0; i < 1000000; i++)
        {
            
        }
        
    }
 
    private class EscapeRunnable implements Runnable
    {
        @Override
        public void run()
        {
            System.out.println(ThreadThisEscape.this.weight);
        }
    }
 
    public static void main(String[] args)
    {
        new ThreadThisEscape();
    }
}


this逃逸就是说在构造函数返回之前其他线程就持有该对象的引用,调用尚未构造完全的对象的方法可能引发错误。
--------------------- 
作者:aitangyong 
来源:CSDN 
原文:https://blog.csdn.net/aitangyong/article/details/25122741 
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(并发编程)