多线程/并发笔记:Java并发编程之this逃逸问题

原创 2017年09月13日 17:00:02

this逃逸是指在构造函数返回之前其他线程就持有该对象的引用. 调用尚未构造完全的对象的方法可能引发令人疑惑的错误。

this逃逸经常发生在构造函数中启动线程或注册监听器时, 如:

package com.mungo.lily.demo;

import com.mungo.lily.domain.MessageInfo;

public class ThisEscape {
    private String name;
    private Thread t;

    public static void main(String args[]) {
        try {
            ThisEscape te = new ThisEscape("ThisEscape ");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public ThisEscape() throws InterruptedException {
        t = new Thread(new EscapeRunnable());
        t.start();
        //其他操作。。。。
        Thread.sleep(2000);
        this.name = name;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

上面的代码在编译的时候是没有问题的,可是在运行时报错。
这里写图片描述
这是因为,通过ThisEscape.this就调用了name的对象, 但是此时name对象可能还没有初始化完成, 所以输出的值就是null,即发生了外围类的this引用的逃逸。

所以,this逃逸问题的是需要避免的。因为这种问题在debug时是不容易发现的。上面的相同的代码,如果在System.out.println(ThisEscape.this.info.toString());这行代码的地方加个断点,等待一会,输出的时候是有值。
这里写图片描述
那么如何避免这个问题呢?当然,在构造函数中创建Thread对象是没有问题的, 但是不要启动Thread,所以可以提供一个init方法, 去启动进程,以保证在进程启动的时候所有的外围类对象都已完成初始化。即:

package com.mungo.lily.demo;

import com.mungo.lily.domain.MessageInfo;

public class ThisEscape {
    private String name;
    private Thread t;

    public static void main(String args[]) {
        try {
            ThisEscape te = new ThisEscape("ThisEscape");
            //启动进程
            te.init();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public ThisEscape(String name) throws InterruptedException {
        t = new Thread(new EscapeRunnable());
        //构造方法不启动进程
        //t.start();

        Thread.sleep(2000);
        this.name = name;
    }

    //启动进程
    public void init(){
        t.start();
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

以上是参考Java并发编程之this逃逸问题,如有理解不当地方请指正。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

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

《java并发编程实践》的第三章,对象的发布和逸出,作者提到了2种常见的对象逸出情况:在构造函数中注册事件监听,在构造函数中启动新线程。示例代码如下: public class ThisEscape ...

java多线程中this与Thread.currentThread()返回值的引用问题

java多线程中this与Thread.currentThread()返回值的引用问题

深入Java多线程和并发编程

  • 2014-08-25 17:03
  • 3.83MB
  • 下载

Boost并发编程(多线程)编译链接所遇到的问题

在Boost库使用过程中,一般仅仅需要配置好头文件路径、库文件路径即编程。在实际的编程中,对于常规的Boost知识(时间、格式化、字符串处理)使用一般无大碍,只是要注意一下命名空间的导入即可。但是对于...

Java 多线程 并发编程

一、多线程1、操作系统有两个容易混淆的概念,进程和线程。 进程:一个计算机程序的运行实例,包含了需要执行的指令;有自己的独立地址空间,包含程序内容和数据;不同进程的地址空间是互相隔离的;进程拥有各种...

Java 多线程与并发编程专题

Java 线程基础Java 多线程开发线程安全与同步并发控制非阻塞套接字(NIO)Java 5 中的并发JDK 7 中的 Fork/Join 模式相关书评 Java 平台提供了一套广泛而功能强大...

Java 多线程 并发编程

一、多线程 1、操作系统有两个容易混淆的概念,进程和线程。 进程:一个计算机程序的运行实例,包含了需要执行的指令;有自己的独立地址空间,包含程序内容和数据;不同进程的地址空间是互相隔离的;...

Java 多线程 并发编程

Java 多线程 并发编程
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)