设计线程安全的类
在设计线程安全类的过程中, 需要包含一下三个基本要素:
- 找出构成对象状态的所有变量
- 对象的域构成对象的状态
- 找出约束状态变量的不变性条件, 以及先后验条件
- 不变性条件比如NumberRange类包含俩变量, 要求下界值小于等于上界值, 不变性条件会带来原子性需求, 相关变量需要在一个原子操作中
- 先验条件比如删除元素前, 需要判断队列不能为空, 这是依赖状态的操作
- 建立对象状态的并发访问管理策略
线程封闭
- 对象可以封闭在类的一个实例, 或者作为类的一个私有成员中, 或者封闭在某个作用域内, 例如作为一个局部变量, 再或者封闭在线程内
- 将数据封装在对象内部, 可以将数据的访问限制在对象的方法之上, 从而更容易确保线程在访问数据时总能持有正确的锁, 实例封闭是构建线程安全类的一个最简单方式
Java监视器模式
java监视器模式是指把对象的所有可变状态都封装起来, 并由对象自己的内置锁来保护
补充: 也可以使用私有锁对象, 好处是客户代码可以通过共有方法来获取正确的锁对象, 以便参与到同步策略中
在现有的线程安全类中添加功能
使用继承来拓展
- 并非所有的类都像Vector那样状态向子类公开, 因此也就不适合这种方法
- 如果底层的类改变了同步策略并选择了不同的锁来保护它的状态变量, 那么子类会被破坏, 因为在策略改变后无法再使用正确的锁来控制对基类状态的并发访问
使用辅助类
- 注意外部辅助类与客户端需要使用同一个锁
- 脆弱, 将客户端的加锁代码放到与客户端完全无关的其它类中
组合
- 通过自身的内置锁增加了一层额外的加锁, 它并不关心底层的List是否是线程安全的, 即使List不是线程安全的或者修改了它的加锁实现, ImprovedList也会提供一致的加锁机制来实现线程安全性