如何通过线程安全的组件组合设计线程安全的类?
首先要封装所有状态,封装简化了安全类的实现过程。
设计线程安全的类,需考虑三个基本要素
- 找出构成对象状态的所有变量
- 找出约束状态变量的约束条件–>不变性条件和后验条件
- 建立对象状态的并发访问管理策略
要满足对象的状态的约束条件,就需要借助于原子性和封装性。
依赖状态的操作
如果某个操作中包含有基于状态的先验条件(Precondition),如没有则添加,那么这个操作称为依赖状态操作 。
实现等待条件为真才执行的操作的方法有:
内置机制(如等待和通知);现有的类库中的类(如BlockingQueue)。
状态的所有权
对象封装了它拥有的状态,则对象对它封装的状态拥有所有权。
如果发布一个可变对象的引用,就不在独占所有权。
容器类表现为所有权分离,容器类拥有自身的状态,而客户代码则拥有容器内各个对象的状态。
通过封闭和加锁实现线程安全的类
public class PersonSet {
private final Set<Person> mySet = new HashSet<Person>();
public synchronized void addPerson(Person p) {
mySet.add(p);
}
public synchronized boolean containsPerson(Person p) {
return mySet.contains(p);
}
interface Person {
}
}
PersonSet类是线程安全的类,它将状态(mySet )封装起来,并对访问这个状态的方法进行加锁。
但Person类如果是可变的,需要设计成线程安全的类来安全的使用Person对象。
创建线程安全类的策略1 - Java监视器模式
Java监视器模式的对象会把对象的所有可变状态都封装起来,并有对象自己的内置锁来保护。
私有锁
public class PrivateLock {
private final Object myLock = new Object();
Widget widget;
void someMethod() {
synchronized (myLock) {
// Access or modify the state of widget
}
}
}
创建线程安全类的策略2 - 线程安全性的委托
通过对象的组合,将线程安全性委托给现有的线程安全类。
如果一个类是由多个独立且线程安全的状态变量组成,并且在所有的操作中都不包含无效状态的转换,那么可以将线程安全性委托给底层的状态变量。
示例:PersonList将线程安全性委托给底层的线程安全状态变量
public class PersonList {
private final List<Person> myList = new CopyOnWriteArrayList<Person>();//安全性委托
public void addPerson(Person p) {
myList.add(p);
}
public boolean containsPerson(Person p) {
return myList.contains(p);
}
interface Person {
}
}
线程安全性委托要考虑下列问题:
1. 状态变量要是线程安全的。
2. 多个线程安全的状态变量是独立的。
3. 多个线程安全的状态变量有不变性条件约束–不能直接委托,需要对操作加锁。
4. 类含有复合操作– 不能直接委托,需要对操作加锁。
5. 什么条件下可以发布底层的状态变量?
如果一个状态变量是线程安全的,并且没有任何不变性条件约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全地发布这个变量。
在现有的线程安全类中添加功能
1.修改原始的类
2.扩展原始类(继承)
3.扩展原始类的功能,将扩展代码放到一个“辅助类”中–通过客户端加锁。
4.组合–通过客户端加锁。
示例: 扩展原始类的功能
@NotThreadSafe
class BadListHelper <E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public synchronized boolean putIfAbsent(E x) {//和list对象不是同一锁
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
@ThreadSafe
class GoodListHelper <E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public boolean putIfAbsent(E x) {
synchronized (list) {//和list对象是同一个锁
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
}
示例: 组合
@ThreadSafe
public class ImprovedList<T> implements List<T> {
private final List<T> list;
/**
* PRE: list argument is thread-safe.
*/
public ImprovedList(List<T> list) { this.list = list; }
public synchronized boolean putIfAbsent(T x) {
boolean contains = list.contains(x);
if (contains)
list.add(x);
return !contains;
}
// Plain vanilla delegation for List methods.
// Mutative methods must be synchronized to ensure atomicity of putIfAbsent.
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public boolean contains(Object o) {
return list.contains(o);
}
public Iterator<T> iterator() {
return list.iterator();
}
public Object[] toArray() {
return list.toArray();
}
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
public synchronized boolean add(T e) {
return list.add(e);
}
public synchronized boolean remove(Object o) {
return list.remove(o);
}
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
public synchronized boolean addAll(Collection<? extends T> c) {
return list.addAll(c);
}
public synchronized boolean addAll(int index, Collection<? extends T> c) {
return list.addAll(index, c);
}
public synchronized boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
public synchronized boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
public boolean equals(Object o) {
return list.equals(o);
}
public int hashCode() {
return list.hashCode();
}
public T get(int index) {
return list.get(index);
}
public T set(int index, T element) {
return list.set(index, element);
}
public void add(int index, T element) {
list.add(index, element);
}
public T remove(int index) {
return list.remove(index);
}
public int indexOf(Object o) {
return list.indexOf(o);
}
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
public ListIterator<T> listIterator() {
return list.listIterator();
}
public ListIterator<T> listIterator(int index) {
return list.listIterator(index);
}
public List<T> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
public synchronized void clear() { list.clear(); }
}