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

标签: 多线程 并发
189人阅读 评论(0) 收藏 举报
分类:

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逃逸问题

简介 this逃逸是指在构造函数返回之前其他线程就持有该对象的引用. 调用尚未构造完全的对象的方法可能引发令人疑惑的错误, 因此应该避免this逃逸的发生. this逃逸经常发生在构造...
  • zhushuai1221
  • zhushuai1221
  • 2016-04-22 16:57:12
  • 1505

《JAVA并发编程实践》读书笔记(一)

《JAVA并发编程实践》读书笔记(一)2016年8月1日,“妮妲”冲击广东,全市放假1天。托“妮妲”的福,终于有空将近期的阅读整理一下。 最近利用业余时间重读了Brian Goetz的书,觉得受益匪...
  • youngweiquan
  • youngweiquan
  • 2016-08-02 01:04:55
  • 868

《Java并发编程的艺术》读书笔记——Java内存模型

第三章 Java内存模型3.1 内存模型基础3.1.1 并发编程的两个关键问题 线程之间如何通信 java采用共享内存模型隐式通信 线程之间如何同步 共享内存模型模型需要显式指定同步 3.1.2 ...
  • shuxiangxingkong
  • shuxiangxingkong
  • 2016-09-13 10:49:17
  • 500

《java并发编程实战》读书笔记——并发应用

1.使用线程池 当应用需要处理多个任务时,例如一个Web服务器处理它接收到的请求,可以使用线程池。 通过重用现有的线程而不是创建新的线程,可以在处理多个请求时分摊在线程创建和销毁过程中产生的巨大开销。...
  • Great_Smile
  • Great_Smile
  • 2016-01-06 22:11:10
  • 1144

Java并发编程学习路线图

思维导图如下:
  • csujiangyu
  • csujiangyu
  • 2016-05-18 10:08:31
  • 1014

《java并发编程的艺术》读书笔记-第四章java并发的基础

一概述  本文属于《java并发编程的艺术》读书笔记系列,第四章java并发的基础。 4.1线程简介 这里作者介绍了线程的相关知识,如线程、优先级,状态,daemon线程,线程的启动和停止。这里可以...
  • bohu83
  • bohu83
  • 2016-06-21 14:32:49
  • 621

Java并发编程系列之十五:Executor框架

Java使用线程完成异步任务是很普遍的事,而线程的创建与销毁需要一定的开销,如果每个任务都需要创建一个线程将会消耗大量的计算资源,JDK 5之后把工作单元和执行机制区分开了,工作单元包括Runnabl...
  • u011116672
  • u011116672
  • 2016-04-04 17:55:04
  • 5736

《Java并发编程的艺术》读书笔记(一)

并发机制底层实现原理 volatile 使用volatile修饰的变量,在编译的时候会加上LOCK前缀加锁指令,LOCK前缀会使处理器执行当前指令时产生一个LOCK#信号,这个总是会引起显式总线的锁...
  • swbyzx
  • swbyzx
  • 2015-08-27 11:36:18
  • 1504

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

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

Android 并发二三事之Java线程池

最近在项目中接触到了很多有关于多线程方面的东西,并且刚好前段时间看了Java并发编程实战那本说, 所以想将自己所了解到的,以及实际中碰到的问题总结一下。打算首先介绍一下,Java多线程相关的基础,例...
  • MyLero
  • MyLero
  • 2016-11-04 11:34:16
  • 867
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 15万+
    积分: 2218
    排名: 2万+
    博客专栏
    最新评论