设计线程安全的类

设计线程安全的类

将现有的线程安全的组件组合为更大规模的组件或程序。
通过使用封装技术可以使得在不对整个程序进行分析的情况下就可以判断一个类是否是线程安全的。

1 基本要素

1.1 找出对象状态的所有变量

  1. 如果对象中所有的域都是基本类型的变量,那么这些域将构成对象的全部状态
  2. 如果对象的域中引用了其他对象,那么改对象的状态包括被引用的对象的域

final域越多越能简化对象可能状态的分析过程。

1.2 找出约束状态变量的不变条件

状态变量的所有者将决定采用何种加锁协议来维持变量的完整性。

1.2.1 单一状态的有效性
1.2.2 状态转换有效性
1.2.3 多个状态变量的不变性

这些相关变量必须在单个原子操作中进行读取或更新。
如果在一个不变性条件中包含多个变量,那么在执行任何访问相关变量的操作时,都必须持有保护这些变量的锁。

1.3 建立对象状态的并发访问策略

同步策略,定义了如何在不违反对象不变条件或后验证条件的情况下对其状态的访问操作进行协同。

2 依赖状态的操作

如果在某个操作中包含有基于状态验证的先验条件,那么这个操作被称为依赖状态的操作。

3 状态的所有权

状态变量的所有者将决定采用何种加锁协议来维持变量状态的完整性。

4 实现策略

4.1 实例封闭

通过将封闭机制与合适的加锁策略结合起来,可以确保以线程安全的方式来使用非线程安全的对象。
被封闭对象一定不能超出他的作用域。包括:

  1. 类的一个实例,作为类的私有成员
  2. 某个作用域,局部变量
  3. 线程内

Java监视器模式
遵循Java监视器模式的对象会把对象的所有可变状态都封装起来,并由对象自己的内置锁来保护。
私有内置锁对象可以将锁封装起来,使客户端代码无法得到锁,但客户端代码可以通过公有方法访问锁。

4.2 线程安全性的委托

将线程安全性委托给现有的线程安全类。
我们可以将线程安全性委托给多个状态变量,只要这些变量是彼此独立的,即组合而成的类并不会在其包含的多个状态变量上增加任何不变性条件。
发布底层状态:
如果一个状态变量是线程安全的,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全的发布这个变量。

4.3 扩展现有安全类

4.3.1 修改原始类

一般情况下很难做到。

4.3.2 扩展原始类

不够健壮,一般情况下需要分析父类的加锁策略,并与父类加锁策略的实现保持严格的一致性。

4.3.3 客户端加锁

相当脆弱,需要分析具体实现的加锁策略。

4.3.4 组合

鼓励使用。
自定义加锁策略,对底层具体实现不做要求。

wenxinzizhu wechat
扫一扫,添加我的微信,一起交流共同成长(备注为技术学习)