Java线程安全性中的对象发布和逸出
2017-08-07 17:49
183 查看
转自: http://www.cnblogs.com/yulinfeng/p/5975728.html
发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系。
什么是发布?简单来说就是提供一个对象的引用给作用域之外的代码。比如return一个对象,或者作为参数传递到其他类的方法中。
什么是逸出?如果一个类还没有构造结束就已经提供给了外部代码一个对象引用即发布了该对象,此时叫做对象逸出,对象的逸出会破坏线程的安全性。
概念我们知道了,可我们要关注什么地方呢?我们要关注的时候就是逸出问题,在不该发布该对象的地方就不要发布该对象,例如以下代码:
states变量作用域是private而我们在getStates方法中却把它发布了,这样就称为数组states逸出了它所在的作用域。
然而更加隐蔽和需要我们注意的是this逸出,这个问题要引起重点关注。什么是this逸出?观察以下代码:
在构造方法中我们定义了一个匿名内部类,匿名内部类是一个事件监听类,当事件监听类注册完毕后,实际上我们已经将EventListener匿名内部类发布出去了,而此时我们实际上已经携带了this逸出,重点在于这个时候我们还有一些初始化工作没有做完(代码11行之后),这也就是上面所说的,一个类还没有构造结束我们已经将发布了。那怎么来避免this逸出呢?既然我们没有构造完构造函数,那我们就将构造函数构造完嘛,将构造函数定义为private作用域。如以下代码所示:
我们首先将构造函数设定为private,其次我们在构造函数未完成时不将对象进行发布,而是使用工厂方法,在工厂方法newInstance中待构造函数执行完毕后再将对象进行发布(代码中即为registenerListener注册监听)。这实际上就是修改为了构造完毕->发布对象的串行执行模式,而不是之前的异步模式,这样就不会给我们带来线程安全性的问题。
不积跬步,无以至千里;不积小流,无以成江海。
发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系。
什么是发布?简单来说就是提供一个对象的引用给作用域之外的代码。比如return一个对象,或者作为参数传递到其他类的方法中。
什么是逸出?如果一个类还没有构造结束就已经提供给了外部代码一个对象引用即发布了该对象,此时叫做对象逸出,对象的逸出会破坏线程的安全性。
概念我们知道了,可我们要关注什么地方呢?我们要关注的时候就是逸出问题,在不该发布该对象的地方就不要发布该对象,例如以下代码:
1 class UnsafeStates{ 2 private String[] states = new String[]{"AK", "AL"}; 3 4 public String[] getStates(){ 5 return states; 6 } 7 }
states变量作用域是private而我们在getStates方法中却把它发布了,这样就称为数组states逸出了它所在的作用域。
然而更加隐蔽和需要我们注意的是this逸出,这个问题要引起重点关注。什么是this逸出?观察以下代码:
1 public class ThisEscape{ 2 private int value; 3 public ThisEscape(EventSource source){ 4 source.registerListener{ 5 new EventListener(){ 6 public void onEvent(Event e){ 7 doSomething(e); 8 } 9 } 10 } 11 //一些初始化工作 12 value = 7; 13 } 14 15 public void doSomething(Event e){ 16 System.out.println(value); 17 } 18 19 }
在构造方法中我们定义了一个匿名内部类,匿名内部类是一个事件监听类,当事件监听类注册完毕后,实际上我们已经将EventListener匿名内部类发布出去了,而此时我们实际上已经携带了this逸出,重点在于这个时候我们还有一些初始化工作没有做完(代码11行之后),这也就是上面所说的,一个类还没有构造结束我们已经将发布了。那怎么来避免this逸出呢?既然我们没有构造完构造函数,那我们就将构造函数构造完嘛,将构造函数定义为private作用域。如以下代码所示:
1 public class SafeListener{ 2 private final EventListener listener; 3 4 private safeListener(){ 5 listener = new EventListener(){ 6 public void onEvent(Event e){ 7 doSomething(e); 8 } 9 } 10 } 11 12 public static SafeListener newInstance(EventSource source){ 13 SafeListener safeListener = new SafeListener(); 14 safeListener.registerListener(safeListener.listener); 15 16 return safeListener; 17 } 18 }
我们首先将构造函数设定为private,其次我们在构造函数未完成时不将对象进行发布,而是使用工厂方法,在工厂方法newInstance中待构造函数执行完毕后再将对象进行发布(代码中即为registenerListener注册监听)。这实际上就是修改为了构造完毕->发布对象的串行执行模式,而不是之前的异步模式,这样就不会给我们带来线程安全性的问题。
不积跬步,无以至千里;不积小流,无以成江海。
相关文章推荐
- Java线程安全性中的对象发布和逸出
- Java 并发编程(二)对象的发布逸出和线程封闭
- Java 并发编程(二)对象的公布逸出和线程封闭
- Java多线程安全之对象的发布和溢出、线程封闭详解
- Java并发系列(二)线程安全与对象的发布
- Java并发编程之线程安全性和对象的的共享
- JAVA并发编程学习笔记------对象的可见性及发布逸出
- [转] Java线程问题:当一个目标对象被多个线程共享时候
- 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题
- 【JAVA并发学习三】创建线程对象
- Java多线程编程基础之线程对象
- java并发编程实践学习(四)对象的发布和逸出之this逃逸
- 从头认识多线程-4.1 对象的发布(Publish)、逸出(Escape)以及逸出的解决方案
- 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题
- Java线程(八):锁对象Lock-同步问题更完美的处理方式
- Java线程(八):锁对象Lock-同步问题更完美的处理方式
- Java并发编程学习笔记之发布逸出
- Java线程(八):锁对象Lock-同步问题更完美的处理方式
- java线程基础巩固---构造Thread对象你也许不知道的几件事
- Java线程同步:synchronized锁住的是代码还是对象