0%

并发编程4-对象的组合

对象的组合

本章将介绍一些组合模式,这些模式能够使一个类更容易成为线程安全的,并且在维护这些类时不会无意中破坏类的安全性保证。

设计线程安全的类

在设计线程安全类的过程中,需要包含以下三个基本要素:

  • 找出构成对象状态的所有变量
  • 找出约束状态变量的不变性条件
  • 建立对象状态的并发访问管理策略

收集同步需求

要确保的类的线程安全性,就需要确保它的不变性条件不会在并发访问的情况下被破坏,这就需要对其状态进行推断。

不变性条件是指变量的取值范围约束,后验条件是指状态改变的时候值是否合法。
如果不了解对象的不变性条件与后验条件,那么就不能确保线程安全性。要满足在状态变量的有效值或状态转换上的各种约束条件,就需要借助于原子性与封装性。

依赖状态的操作

先验条件是基于前一个状态的操作,例如不能从空队列中移除一个元素,这个被称为依赖状态的操作。
在单线程程序中,如果某个操作无法满足先验条件,那么就只能失败。但在并发程序中先验条件可能会由于其他线程执行的操作而变成真。在并发程序中要一只等到先验条件为真,然后再执行操作。后面将会介绍JDK提供的BlockingQueue和Semaphore等同步工具类来实现依赖状态的行为。

状态的所有权

许多情况下,所有权与封装性总是相互关联的:对象封装它拥有的状态,反之也成立,即对它封装的状态拥有所有权。

实例封闭

如果某对象不是线程安全的,那么可以通过多种技术使其在多线程程序中安全地使用。你可以确保该对象只能由单个线程访问(线程封闭),或者通过一个锁来保护该对象的所有访问。
将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时总能持有正确的锁。
封闭机制更易于构造线程安全的类,因为当封闭类的状态时,在分析类的线程安全性时就无须检查整个程序。

Java监视器模式

从线程封闭原则及其逻辑推论可以得出Java监视器模式。遵循Java监视器模式的对象会把对象的所有可变状态都封装起来,并由对象自己的内置锁来保护。意思就是对象的属性全部通过同步的方法来访问或者修改。

1
2
3
4
5
6
7
8
9
10
public class PrivateLock {
private final Object myLock = new Object();
Widget widget;

void someMethod() {
synchronized(myLock) {
// 访问或修改Widget的状态
}
}
}

使用私有的锁对象而不是对象的内置锁,有许多优点。私有锁对象可以将锁封装起来,使客户代码无法得到锁,但客户代码可以通过共有方法来访问锁,以便参与到它的同步策略中。