并发编程之对象的发布和逸出
一、对象的发布和逸出
发布(publish)对象意味着其作用域之外的代码可以访问操作此对象。例如将对象的引用保存到其他代码可以访问的地方,或者在非私有的方法中返回对象的引用,或者将对象的引用传递给其他类的方法。
为了保证对象的线程安全性,很多时候我们要避免发布对象,但是有时候我们又需要使用同步来安全的发布某些对象。
逸出即为发布了本不该发布的对象。
使用静态变量引用对象是发布对象最直观和最简单的方式。例如以下代码示例,在示例中我们也看到,由于任何代码都可以遍历我们发布persons集合,导致我们间接的发布了Person实例,自然也就造成可以肆意的访问操作集合中的Person元素。
package com.codeartist;import java.util.HashSet;public class ObjectPublish {public static HashSet<Person> persons ;public void init(){persons = new HashSet<Person>();}}
在非私有的方法内返回一个私有变量的引用会导致私有变量的逸出,例如以下代码
package com.codeartist;import java.util.HashSet;public class ObjectPublish { private HashSet<Person> persons= new HashSet<Person>();public HashSet<Person> getPersons(){return this.persons;}}
发布一个对象也会导致此对象的所有非私有的字段对象的发布,其中也包括方法调用返回的对象。
在构造函数中使用直接初始化或者调用可改写的实例方法都会导致隐式的this逸出也是经常发生的事情,例如以下代码,在EventListener的实例中也通过this隐含的发布了尚未构造完成的ConstructorEscape实例,可能会造成无法预知的结果。
package com.codeartist;public class ConstructorEscape {public ConstructorEscape(EventSource eventSource){eventSource.registerListener(new EventListener(){public void OnEvent(Event e){doSomeThing(e);}});} }
我们可以使用工厂方法防止隐式的this逸出问题,例如以下代码
package com.codeartist;public class ConstructorEscape {private final EventListener listener;private ConstructorEscape(){this.listener= new EventListener(){public void OnEvent(Event e){doSomeThing(e);}}; }public static ConstructorEscape getInstance(EventSource eventSource){ConstructorEscape instance = new ConstructorEscape();eventSource.registerListener(instance.listener);return instance;} }
二、避免对象发布之线程封闭
线程封闭可以使数据的访问限制在单个线程之内,相对锁定同步来说,其实实现线程安全比较简单的方式。
java提供了ThreadLocal类来实现线程封闭,其可以使针对每个线程存有共享状态的独立副本。其通常用于防止对可变的单实例变量和全局变量进行共享,例如每个请求作为一个逻辑事务需要初始化自己的事务上下文,这个事务上下文应该使用ThreadLocal来实现线程封闭。
栈封闭是线程封闭的特例,即数据作为局部变量封闭在执行线程中,对于值类型的局部变量不存在逸出的问题,如果是引用类型的局部变量,开发人员需要确保其不要作为返回值或者其他的关联引用等而被逸出。
三、避免对象发布之不变性
某个对象创建之后就不能修改其状态,那么我们就说这个对象是不可变对象。
由于多线程操作可变状态会导致原子性、可见性一系列问题,所以线程安全性是不可变对象与生俱来的特性。
不可变对象由构造函数初始化状态,并可以安全的传递给任何不可信代码使用。
所有字段标记为final的对象,由于引用字段的对象可能可以直接修改,所以其并不一定是不可变对象,其需要满足以下条件
对象的所有字段都用final标记
对象创建之后任何状态都不能修改
对象不存在this隐式构造函数逸出
package com.codeartist;import java.util.HashSet;public class ObjectPublish { private HashSet<Person> persons= new HashSet<Person>();public ObjectPublish(){ persons.add(new Person("wufengtinghai"));persons.add(new Person("codeartist"));}public Person getPerson(String name){Person result = null;for(Person p : this.persons){if(p.name == name){result = p.Clone();}} return result;} }
四、对象的安全发布
很多时候我们是希望在多线程之间共享数据的,此时我们就必须确保安全的发布共享对象。
要安全的发布一个对象,对象的引用以及对象的状态对其他线程都是可见的,一个正确构造的对象可以通过以下方式安全的发布
在静态构造函数中初始化对象引用
使用volatile和AtomicReferance限定对象引用
使用final限定对象引用
将对象引用保存到有锁保护的字段中
1.不可变对象
任何线程都可以在不需要同步的情况下安全的访问不可变对象及其final字段,如果字段的引用可以改变则需要进行同步。
不可变对象在确保初始化安全的前提,可以自由的发布
有时为了确保不可变对象对于多个线程呈现一致的状态,需要使用同步不可变对象的初始化。
需要具备以上说的三个不变性限制条件。
2.隐式约定不可变对象
实际可以改变对象在发布后不会再改变状态,则此对象成为隐式约定不可变对象。
虽然任何线程都可以无需同步即可安全的访问隐式约定不可变对象,但是由于其本身还是可变的,所以其需要以安全方式进行发布。
3.可变对象
需要使用同步来确保发布和共享的安全性。
五、对象的安全共享
为了确保使用共享对象的安全性,我们需要遵循其既定的规则(例如是否是不可变对象)来确定我们访问对象的方式
不可变对象和隐式约定不可变对象可以直接由多线程并发访问。
线程封闭对象只能由创建线程持有并修改。
自己内部实现安全性的线程安全对象也可以直接由多线程访问。
一般的可变对象只能通过持有锁进行同步来实现安全共享。
并发编程之对象的发布和逸出相关推荐
- 对象的发布与逸出简单理解
目录 对象的发布与逸出简单理解 定义 实战 对象的发布与逸出简单理解 最近来看<并发编程实战>,第3.2节有点疑问,记录一下. 定义 发布:发布(Publish)一个对象的意思是指,使对象 ...
- 《java并发编程实战》读书笔记二 对象的发布与逸出
概念 发布(publishing): 发布一个对象的意思是使它能够被当前范围之外的代码所使用.比如将一个引用存储到其他代码可以访问的地方,在一个非私有的方法中返回这个引用,也可以把它传递到其他类的方法 ...
- 并发编程-08安全发布对象之发布与逸出
文章目录 脑图 概念 示例 不安全的发布对象Demo 对象逸出Demo 小结 代码 脑图 概念 发布对象: 使一个对象能够被当前范围之外的代码所使用,日常开发中比较常见的比如通过类的非私有方法返回对象 ...
- Java对象的发布与逸出
1. 概念 "发布(Publish)"一个对象:使对象能够在当前作用域之外的代码中使用. 例如:将一个指向该对象的引用保到其他代码可以访问的地方,或者在某个非私有的方法中返回该引用 ...
- 多线程5:对象的发布与逸出(线程安全性)
发布:使对象能够在当前作用域之外的代码中使用 逸出:当某个不该被发布的对象被发布时,这种情况称为逸出 发布内部状态将会破坏封装性,并使得程序难以维持不变性条件 当某个对象逸出后,必须对程序进行分析,以 ...
- 逸出 java_【java】知识系谱-基础篇-线程-发布、逸出
java并发编程实战的解释,不够详细,尤其this引用逸出让人理解有些费解,java并发编程实战里面的内容就直接拷贝过来 发布:使对象能够在当前作用域之外的代码中使用 逸出:当某个不该被发布的对象被发 ...
- java 发布和逸出
[转载]:http://www.2cto.com/kf/201310/247738.html 前言 多线程并发环境下,线程安全极为重要.往往一些问题的发生都是由于不正确的发布了对象造成了对象逸出而引起 ...
- 多线程核心8-3:线程三大安全问题之发布与逸出
发布与逸出的概念 发布:对象能够在作用域范围外被使用,则这个对象被发布出去了 逸出:被发布到了不该发布的地方,以下是逸出的两种情况: 方法返回一个private对象 未完成初始化(构造函数还未执行完毕 ...
- java中的逸出是什么意思,发布和逸出-构造过程中使this引用逸出
1.什么是this对象 this就是该对象实例本身 2.何为发布和逸出 发布,就是把对象暴露给他人,这就是为什么会需要用到封装,不能预料到其他第三方会如何使用对象,一不小心可能就被玩坏了 逸出,把不应 ...
最新文章
- 基于PAM认证方式详解
- 2020-10-14 B树 概念添加删除笔记
- Windows内存的一些知识点
- c#4.0新特性之一: Dynamic Lookup (1)
- lua中的require、dofile、loadfile
- EMLOG复制网站文字提醒弹窗源码美化版
- Stack Overflow RToax
- HBASE元数据及数据读取过程
- Eclipse的Servers视图中无法添加Tomcat6/Tomcat7
- python视频换脸下载_FaceSwap下载|Faceswap(AI视频换脸软件) v1.0官方版(附使用教程)...
- EclipseMaven导入Maven项目后在pom.xml出现Missing artifact org.springframework:spring-jdbc:jar:3.2.4.RELEAS
- python 键盘输入立刻反应_win10系统,为什么键盘输入字符后得停顿一下,鼠标点击才有效 例如在wor...
- Python爬虫 爬取豆瓣电影TOP250
- notifyDataSetChanged使用总结
- 对已过去三年来大学生活的总结与建议
- c语言stricmp函数,stricmp ( )【C语言库函数源代码】
- python django 图片管理系统
- 【Python】多线程及threading模块介绍
- 图片文件打开失败:“Could not load image... ...0x89 0x50”
- 企业及时通讯软件源代码销售,功能类似QQ/UC/贸易通