博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java并发编程(三): 对象的组合
阅读量:5777 次
发布时间:2019-06-18

本文共 4631 字,大约阅读时间需要 15 分钟。

hot3.png

对象的组合:

  • 如何将现有的线程安全组件,组合成我们想要的更大规模的程序。

设计线程安全的类:

  • 设计线程安全类的三个要素:

       1.找出构成对象状态的所有变量;

       2.找出约束状态变量的不变性条件;

       3.建立对象状态的并发访问管理策略。

收集同步需求:

  • 如果不了解对象的不变性条件后验条件,那就不能确保线程安全性。要满足在状态变量的有效值状态转换上的各种约束条件,就需要借助原子性封装性

依赖状态的操作:

  • 如果在某个操作中包含有基于状态的先验条件,那么这个操作就称为依赖状态的操作。如在操作前,判断当前状态是否可以进行当前操作。

状态的所有权:

  • 所有权封装性总是相互关联的:对象封装它拥有的状态,即对它封装的状态拥有所有权,当然所有权可以通过传递对象,变成共享所有权

实例封闭:

  • 将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时总能持有正确的锁。
/** * 这里将mySet实例封闭在PersonSet中, * 尽管HashSet是非线程安全类, * 由于mySet是私有且不会逸出的, * 我们通过公共接口提供给外部访问,但加上了PersonSet内置锁保护synchronized, * 因而PersonSet是一个线程安全的类 */@ThreadSafepublic class PersonSet {	private final Set
mySet = new HashSet<>(); public synchronized void addPerson(Person p){ mySet.add(p); } public synchronized boolean containsPerson(Person p){ return mySet.contains(p); }}
  • 封闭机制更易于构造线程安全的类,因为当封闭类的状态时,在分析类的线程安全性时就无须检查整个程序。

Java监视器模式:

  • Java监视器模式的对象会把对象的所有可变状态都封装起来,并由对象自己的内置锁来保护。如Vector, Hashtable等类;
  • 我们也可以通过私有锁来代替内置锁:
public class PrivateLock {	private final Object lock = new Object();		public void methodOne(){		synchronized(lock){			// do sth.		}	}}

线程安全性的委托:

  • 多个线程安全的类组合成的类,不一定就是线程安全的。
/** * 委托的PersonSet * 将内部操作委托给线程安全的类SynchronizedSet * 从而自身也是线程安全的 */@ThreadSafepublic class DelegatingPersonSet {	private final Set
mySet = Collections.synchronizedSet(new HashSet
()); public void addPerson(Person p){ mySet.add(p); } public boolean containsPerson(Person p){ return mySet.contains(p); }}

独立的状态变量:

  • 我们还可以将线程安全性委托给多个状态变量,只要这些状态变量彼此独立(不相关):

/** * 将线程安全性委托给多个彼此独立的状态变量 * VisualComponent使用CopyOnWriteArrayList(线程安全)来保存监听器列表 * keyListeners, mouseListeners彼此独立 * 因此VisualComponent线程安全 */public class VisualComponent {	private final List
keyListeners = new CopyOnWriteArrayList<>(); private final List
mouseListeners = new CopyOnWriteArrayList<>(); public void addKeyListener(KeyListener keyListener){ keyListeners.add(keyListener); } public void removeKeyListener(KeyListener keyListener){ keyListeners.remove(keyListener); } public void addMouseListener(MouseListener mouseListener){ mouseListeners.add(mouseListener); } public void removeMouseListener(MouseListener mouseListener){ mouseListeners.remove(mouseListener); }}

当委托失效时:

  • 当类内部多个状态变量,他们之间存在不变性条件,即使这些状态变量各自是线程安全的,那么该类不一定就线程安全:
/** * NumberRange不足以保护它的不变性条件 * 并发环境下不安全 */ @NotThreadSafepublic class NumberRange {	//不变性条件: lower <= upper	private final AtomicInteger lower = new AtomicInteger();	private final AtomicInteger upper = new AtomicInteger();		public void setLower(int i){		if (i > upper.get()){ //不安全的检查			throw new IllegalArgumentException("lower can't > upper");		}		lower.set(i);	}		public void setUpper(int i){		if (i < lower.get()){ //不安全的检查			throw new IllegalArgumentException("lower can't > upper");		}		upper.set(i);	}}
  • 如果一个类是由多个独立线程安全的状态变量组成,并且在所有的操作中都不包含无效状态转换,那么可以将线程安全性委托给底层的状态变量。

发布底层的状态变量:

  • 如果一个状态变量是线程安全的,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全地发布这个变量,例如发布上面VisualComponent的keyListeners, mouseListeners。

在现有的线程安全类中添加功能:

  • 通过扩展类,来添加功能。
/** * 通过扩展实现非重复Vector */public class NoRepeatVector
extends Vector
{ public synchronized boolean putIfAbsent(E e){ boolean exist = contains(e); if (!exist) add(e); return exist; }}

客户端加锁机制:

  • 客户端加锁:对于使用某个对象X的客户端代码,使用X本身用于保护其状态的锁来保护这段客户端代码。
/** * 这段客户端代码看似线程安全, * 但其实并不安全,因为锁住的对象不正确, * 这里仅是锁住ListHelper对象,但list对象并没有被锁住, * 其他客户端仍可在不安全情况下对list进行操作 */@NotThreadSafepublic class ListHelper
{ public List
list = Collections.synchronizedList(new ArrayList
()); public synchronized boolean putIfAbsent(E x){ boolean absent = !list.contains(x); if (absent) list.add(x); return absent; }}
所以上面的代码,我们应该对list加锁,而不是ListHelper对象:
@ThreadSafepublic class SafeListHelper
{ public List
list = Collections.synchronizedList(new ArrayList
()); public boolean putIfAbsent(E x){ synchronized (list) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } }}

组合:

  • 当为现有的类添加一个原子操作时,有一种更好的方法:组合(Composition)。
/** * 通过组合实现"若没有则添加" 下午4:48:42 */@ThreadSafepublic class improvedList
implements List
{ private final List
list; public improvedList(List
list) { this.list = list; } public synchronized boolean putIfAbsent(T t){ boolean absent = !list.contains(t); if (absent) list.add(t); return absent; } @Override public synchronized int size() { return list.size(); }       ...}

将同步策略文档化:

  • 在文档中说明客户代码需要了解的线程安全性保证,以及代码维护人员需要了解的同步策略

不吝指正。

转载于:https://my.oschina.net/indestiny/blog/211957

你可能感兴趣的文章
springmvc+swagger2
查看>>
软件评测-信息安全-应用安全-资源控制-用户登录限制(上)
查看>>
我的友情链接
查看>>
Java Web Application 自架构 一 注解化配置
查看>>
如何 debug Proxy.pac文件
查看>>
Python 学习笔记 - 面向对象(特殊成员)
查看>>
Kubernetes 1.11 手动安装并启用ipvs
查看>>
Puppet 配置管理工具安装
查看>>
Bug多,也别乱来,别被Bug主导了开发
查看>>
sed 替换基础使用
查看>>
高性能的MySQL(5)创建高性能的索引一B-Tree索引
查看>>
oracle备份与恢复--rman
查看>>
图片变形的抗锯齿处理方法
查看>>
Effective C++ Item 32 确保你的 public 继承模子里出来 is-a 关联
查看>>
phpstorm安装laravel-ide-helper实现自动完成、代码提示和跟踪
查看>>
python udp编程实例
查看>>
TortoiseSVN中图标的含义
查看>>
js原生继承之——构造函数式继承实例
查看>>
linux定时任务的设置
查看>>
[CareerCup] 13.3 Virtual Functions 虚函数
查看>>