【转载】:http://www.2cto.com/kf/201310/247738.html

前言

多线程并发环境下,线程安全极为重要。往往一些问题的发生都是由于不正确的发布了对象造成了对象逸出而引起的,因此如果系统开发中需要发布一些对象,必须要做到安全发布,以免造成安全隐患。
发布和逸出 
所谓发布对象是指使一个对象能够被当前范围之外的代码所使用。所谓逸出是指一种错误的发布情况,当一个对象还没有构造完成时,就使它被其他线程所见,这种情况就称为对象逸出。在我们的日常开发中,经常要发布一些对象,比如通过类的非私有方法返回对象的引用,或者通过公有静态变量发布对象。如下面这些代码所示:
 class Unsafepublish { private String[] states={"AK","AL"};public String[] getStates(){  return states;
}publicstaticvoid main(String[] args) {UnSafeStates safe = newUnSafeStates();System.out.println(Arrays.toString(safe.getStates()));safe.getStates()[1] = "c";System.out.println(Arrays.toString(safe.getStates()));}
}
输出结果[AL,KL] 
[AL,c]
以上代码通过public访问级别发布了类的域,在类的外部任何线程都可以访问这些域,这样发布对象是不安全的,因为我们无法假设,其他线程不会修改这些域,从而造成类状态的错误。还有一种逸出是在构造对象时发生的,它会使类的this引用发生逸出,从而使线程看到一个构造不完整的对象,如下面代码所示:
public class Escape{ private int thisCanBeEscape = 0;public Escape(){new InnerClass();}private classInnerClass { public InnerClass() { //这里可以在Escape对象完成构造前提前引用到Escape的private变量System.out.println(Escape.this.thisCanBeEscape);}}public static void main(String[] args) { newEscape();}
}
上面的内部类的实例包含了对封装实例隐含的引用,这样在对象没有被正确构造之前,就会被发布,有可能会有不安全因素。 
一个导致this引用在构造期间逸出的错误,是在构造函数中启动一个线程,无论是隐式启动线程,还是显式启动线程,都会造成this引用逸出,新线程总会在所属对象构造完毕前看到它。所以如果要在构造函数中创建线程,那么不要启动它,而应该采用一个专有的start或initialize方法来统一启动线程。我们可以采用工厂方法和私有构造函数来完成对象创建和监听器的注册,这样就可以避免不正确的创建。 记住,我们的目的是,在对象未完成构造之前,不可以将其发布。 
安全发布对象 
如果不正确的发布了可变对象,那么会导致两种错误。首先,发布线程以外的任何线程都可以看到被发布对象的过期值;其次更严重的情况是,线程看到的被发布对象的引用是最新的,然而被发布对象的状态却是过期的。如果一个对象是可变对象,那么它就要被安全发布,通常发布线程与消费线程必须同步化。一个正确创建的对象可以通过下列条件安全发布:
1、通过静态初始化器初始化对象引用。 
2、将发布对象的引用存储到volatile域或者具有原子性的域中(如:java5.0中的AtomicReference)。 
3、将发布对象引用存放到正确创建的对象的final域中。 
4、将发布对象引用存放到由锁保护的域中(如:同步化的容器)。 
如果要发布一个被静态创建的对象,最简单的方式就是使用静态初始化器,如下面代码所示:public static Holder holder=new Holder();静态初始化器由JVM在类初始化时执行,JVM在执行静态变量的初始化时会有内在同步保护,因此可以保证对象的安全发布。 
高效不可变对象 
有些对象在发布后就不会被修改,其他线程要在没有额外同步的情况下安全的访问它们,此时安全的发布就是至关重要的。所有的安全发布机制都能保证,只要一个对象在发布当时的状态对所有访问线程都可见,那么到它的引用也都可见。如果发布时的状态不会再改变,那么就必须确保任意访问是安全的。
一个对象是可变的,但是它的状态不会在发布后被修改,这样的对象称作“高效不可变对象”。这种对象没有满足我在上一篇文章中所说的不可变对象的条件,但是这些对象在发布后可以被简单的当做不可变对象来使用,另外由于减少了同步,使用它们还会提高效率。如下面代码所示:
public Map<String,Date> lastlogin=Collections.synchonizedMap(new HashMap<String,Date>());
Date对象本身是可变的,每当Date被跨线程来访问都要使用锁来确保访问安全。但是此时我们却可以把它当作一个不可变对象来使用,因为我们将Date对象置入了一个线程安全的HashMap容器中,此时访问这些Date对象值就不再需要额外的同步了。因此任何线程都可以在没有额外同步的情况下安全的使用一个高效不可变对象,但前提是这些对象必须被安全发布,即必须满足上面提到的安全发布条件。 
安全地共享对象 
现在我们来总结一下,在并发 编程中的一些安全共享对象的策略。
1、线程限制:一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改。
2、共享只读:一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不能修改它。
3、线程安全对象:一个线程安全的对象或者容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通过公共接口随意访问它。
4、被守护对象:被守护对象只能通过获取特定的锁来访问

java 发布和逸出相关推荐

  1. java中的逸出是什么意思,发布和逸出-构造过程中使this引用逸出

    1.什么是this对象 this就是该对象实例本身 2.何为发布和逸出 发布,就是把对象暴露给他人,这就是为什么会需要用到封装,不能预料到其他第三方会如何使用对象,一不小心可能就被玩坏了 逸出,把不应 ...

  2. 并发编程之对象的发布和逸出

    一.对象的发布和逸出 发布(publish)对象意味着其作用域之外的代码可以访问操作此对象.例如将对象的引用保存到其他代码可以访问的地方,或者在非私有的方法中返回对象的引用,或者将对象的引用传递给其他 ...

  3. 多线程核心8-3:线程三大安全问题之发布与逸出

    发布与逸出的概念 发布:对象能够在作用域范围外被使用,则这个对象被发布出去了 逸出:被发布到了不该发布的地方,以下是逸出的两种情况: 方法返回一个private对象 未完成初始化(构造函数还未执行完毕 ...

  4. 对象的发布与逸出简单理解

    目录 对象的发布与逸出简单理解 定义 实战 对象的发布与逸出简单理解 最近来看<并发编程实战>,第3.2节有点疑问,记录一下. 定义 发布:发布(Publish)一个对象的意思是指,使对象 ...

  5. Java并发编程(五):Java线程安全性中的对象发布和逸出

    发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外 ...

  6. 逸出 java_【java】知识系谱-基础篇-线程-发布、逸出

    java并发编程实战的解释,不够详细,尤其this引用逸出让人理解有些费解,java并发编程实战里面的内容就直接拷贝过来 发布:使对象能够在当前作用域之外的代码中使用 逸出:当某个不该被发布的对象被发 ...

  7. 《java并发编程实战》读书笔记二 对象的发布与逸出

    概念 发布(publishing): 发布一个对象的意思是使它能够被当前范围之外的代码所使用.比如将一个引用存储到其他代码可以访问的地方,在一个非私有的方法中返回这个引用,也可以把它传递到其他类的方法 ...

  8. Java对象的发布与逸出

    1. 概念 "发布(Publish)"一个对象:使对象能够在当前作用域之外的代码中使用. 例如:将一个指向该对象的引用保到其他代码可以访问的地方,或者在某个非私有的方法中返回该引用 ...

  9. 安全发布对象-发布与逸出

    发布对象 简单来说就是提供一个对象的引用给作用域之外的代码.比如return一个对象,或者作为参数传递到其他类的方法中. 不安全的发布对象示例: @Slf4j @NotThreadSafe publi ...

最新文章

  1. 你的vs.net 2005过期了吗?
  2. 《圣洁》的读后感作文3000字
  3. 工作的未来:敏捷人士瑞典大会上午议程回顾
  4. 《VC++深入详解》学习笔记 第一章 Windows程序内部运行机制
  5. springcloud 注解 @EnableDiscoveryClient 与 @EnableEurekaClient 的区别
  6. 教你如何进入有密码的 XP 系统(下)
  7. typecho博客主题 “Freedom-冷文”
  8. mysql优化php面试_php面试专题---18、MySQL查询优化考点
  9. Ubuntu14.04如何备份和恢复系统
  10. 超棒的30款JS类库和工具
  11. java左右值_为什么C/C++等少数编程语言要区分左右值?
  12. 如何将ImageRanger与外部存储一起使用NAS或USBUSB驱动器?
  13. 从零开始的机器人比赛(一)——项目准备篇
  14. srs之服务搭建+OBS推流(简单记录)
  15. Elasticsearch LBS 的简单应用
  16. python 压缩算法_lzma — 用 LZMA 算法压缩
  17. (热更新相关)CocoaChina 2013春季开发者大会:《大掌门》欧阳刘彬--基于Cocos2d-x引擎开发经验分享
  18. elasticsearch: RequestError(400, ‘parse_exception‘, ‘unknown key [mapping] for create index‘)
  19. 解决java.lang.IllegalArgumentException:Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are requir
  20. 微信开发整理生成jar包

热门文章

  1. 承德算命大师解读命与运的奥秘,承德算命大师预测指导
  2. RNAseq生信分析流程简介
  3. 计算机硬件甩,计算机硬件 篇一:手把手教你更新CPU微码-x99平台最后的挣扎
  4. fortran:计算第二类椭圆积分
  5. excel2007如何筛选后复制粘贴
  6. 基于物联网的校园直饮水管理系统(2022年湖南省物联网应用创新竞赛(技能赛))
  7. android黑盒子调用,[原创]Android群控黑盒调用 - Sekiro食用手册
  8. windows10简单试用多图,连薛定谔的猫都杀死了
  9. OpenCV实现PS2018中的SmartBlur美颜算法
  10. 蓝桥杯 算法提高 回文串