Java并发编程(六)发布与逸出
"发布(Publish)"一个对象的意思指,使对象能够在作用域之外的代码中使用。
例如:
将一个指向该对象的引用保存到其他代码可以访问的地方
在一个非私有的方法中返回该引用
将引用传递到其他类的方法中
有时候要确保对象及其内部状态不被发布,但是某些情况下又需要发布。
如果在发布时要确保线程安全性,则可能需要同步。
发布内部状态可能会破坏封装性,并使得程序难以维持不变性条件。
比如在对象构造完成之前就发布该对象,就会破坏线程安全性。
当某个不应该被发布的对象被发布时,这种情况就叫做"逸出"。
逸出的例子:
public class PublishDemo {
public static Set<Integer> intSet;
public void initialize() {
intSet = new HashSet<>();
}
}
在发布某个对象的时候,可能会间接发布其他对象。比如上面代码中的不仅Set这个集合会被发布出去,Set中的Integer对象也会被发布出去。
public class UnsafeStates {
private String[] states = new String[] {"AK", "47"};
public String[] getStates() {
return states;
}
}
简而言之,就是本来一个人可以经手处理的事情,现在搞得n多个人都可以插上一手了,你说安全不安全。当某个对象逸出之后,必须要假设某个类或者线程会误用该对象。这正是需要封装的原因:封装能够使得对程序的正确性进行分析变得可能,并使得无意中破坏设计约束条件变得更难。
还有一种发布对象或其内部状态的机制就是发布一个内部的类实例。
public class PublishInnerClass {
public PublishInnerClass(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
System.out.println("heheda");
}
}
);
}
class EventSource {
public void registerListener(EventListener eventListener) {
// 暴露出去了
}
}
}
不要在构造过程中使this逸出。
在构造过程中使this引用逸出的一个常见错误是,在构造函数中启动一个线程。当对象在其构造函数中创建一个线程时,无论是显式创建(通过将它传递给构造函数)还是隐式创建(由于Thread或Runnable是该对象的一个内部类),this引用都会被新创建的线程共享。
在对象尚未完全构造之前,新的线程就可以看见她。在构造函数中创建线程并没有错误,但最好不要立即启动它,而是通过一个start或initialize方法启动。在构造函数中调用一个可改写的实例方法时(既不是私有方法,也不是终结方法),同样会导致this引用在构造过程中逸出。
新技能
如果想在构造函数中注册一个事件监听器或启动线程,那么可以使用一个私有构造函数和一个公共的工厂方法(Factory Method),从而避免不正确的构造过程。
public class SafeListener {
private final EventListener listener;
private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
System.out.println("呵呵哒");
}
};
}
class EventSource {
public void registerListener(EventListener listener) {
}
}
public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
结论一:当注册的事件监听器监听到某一个事件发生时,会启用一个新的线程去执行相关的事情。(这个我们在代码中手动启动了一个线程来模拟,在没有监听器注册的时候,启动的线程会自动的阻塞!)
结论二:在外部内中初始化一个内部类的对象时,此内部类的对象保留了一个外部内对象的一个引用。这是java自带的一个机制,这在java中这种机制叫做"synthetic"。通过断点调试我们可以清晰的看到这种实现。
Java并发编程(六)发布与逸出的更多相关文章
- 【Java并发编程六】线程池
一.概述 在执行并发任务时,我们可以把任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程,只要池里有空闲的线程,任务就会分配一个线程执行.在线程池的内部,任务被插入一个阻塞队列(Blo ...
- Java并发编程 (六) 线程安全策略
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.不可变对象-1 有一种安全的发布对象,即不可变对象. 1.不可变对象需要满足的条件 ① 对象创建以后 ...
- Java并发编程(五):Java线程安全性中的对象发布和逸出
发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外 ...
- Java并发编程(六):Java里实现对象安全发布的四种方式
接上篇,首先要了解什么是对象的发布与逸出? Java里安全发布对象的四种方法1.单例(注意懒汉和饿汉的区别)2.静态属性,注意类里的静态域和静态代码块的顺序有要求3.枚举4.final
- Java线程安全性中的对象发布和逸出
发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外 ...
- 《java并发编程实战》读书笔记2--对象的共享,可见性,安全发布,线程封闭,不变性
这章的主要内容是:如何共享和发布对象,从而使它们能够安全地由多个线程同时访问. 内存的可见性 确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化. 上面的程序中NoVisibility可能 ...
- java并发编程笔记(四)——安全发布对象
java并发编程笔记(四)--安全发布对象 发布对象 使一个对象能够被当前范围之外的代码所使用 对象逸出 一种错误的发布.当一个对象还没构造完成时,就使它被其他线程所见 不安全的发布对象 某一个类的构 ...
- java 发布和逸出
[转载]:http://www.2cto.com/kf/201310/247738.html 前言 多线程并发环境下,线程安全极为重要.往往一些问题的发生都是由于不正确的发布了对象造成了对象逸出而引起 ...
- Java并发编程(六)volatile关键字解析
由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识. 一.内存模型的相关概念 Java内存模型规定所有的变量都是存在 ...
- Java并发编程的艺术(六)——线程间的通信
多条线程之间有时需要数据交互,下面介绍五种线程间数据交互的方式,他们的使用场景各有不同. 1. volatile.synchronized关键字 PS:关于volatile的详细介绍请移步至:Java ...
随机推荐
- Mybatis添加用户&&Mybatis添加用户返回ID
(1)添加用户(添加User记录) <!--插入用户 --> <insert id="insertUser" parameterType="com.so ...
- iOS中的场景转换机制的浅显分析
目前Apple推荐的场景转换的方法有以下几个: 一般的跳转方法: presentViewController Discussion In a horizontally compact environm ...
- 怎么在VS2010中打开VS2013的项目
其实VS2010与VS2013上的sln文件没有本质的区别.打不开的原因是什么呢?其实原因很简单,两者开头的软件信息不同.因此造成低版本VS的不识别. VS2013版本vs.sln文件开头的软件信息: ...
- VB6的UTF8编码解码
'UTF-8编码 Public Function UTF8Encode(ByVal szInput As String) As String Dim wch As String D ...
- 微信php分享页面自定义标题与内容
1.因为现在分享页面,发给朋友或者朋友圈都没办法自定义标题.图片和内容,所以必须要有微信公众号 2.如果有微信公众号可直接登录,如果没有要注册,注册完或者登录了 3.查看你的权限,左侧最下面开发的接口 ...
- 刷新神经网络新深度:ImageNet计算机视觉挑战赛微软中国研究员夺冠
微软亚洲研究院首席研究员孙剑 世界上最好计算机视觉系统有多精确?就在美国东部时间12月10日上午9时,ImageNet计算机视觉识别挑战赛结果揭晓——微软亚洲研究院视觉计算组的研究员们凭借深层神经网络 ...
- 【HTTPS双向加密认证】
HTTPS单向认证和双向认证 nearzk-osc 发布时间: 2015/07/30 15:27 阅读: 4177 收藏: 178 点赞: 6 评论: 3 一.背景&概念 HTTPS:在htt ...
- ubuntu下wine操作usb串口
呃,换成ubuntu后想玩下文曲星,貌似没有linux下的下载工具,只好用wine. 用的是ch340的usb转串口,不得不说ubuntu果然集大成,这些驱动都有了,用minicom设置设备为/dev ...
- asyncio NetMQ 解决方案编译问题
程序集代码 (原) <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <VersionPrefix& ...
- 在 Word 中的受支持的区域设置标识符的列表
这篇文章包含当前可用的区域设置 ID (LCID) 语言代码的列表. 概要 这篇文章包含当前可用的区域设置 ID (LCID) 语言代码的列表. 区域设置 ID (LCID): 由 Microso ...