前言:本章将介绍一些组合模式,这些模式能够使一个类更容易设计成线程安全的,并且在维护这些类时不会无意中破坏类的安全性保证。
4.1 设计线程安全的类
在设计线程安全的类过程中,需要包含以下三个基本要素:
(1)找出构成对象状态的所有变量。
(2)找出约束状态变量的不变性条件。
(3)建立对象状态的并发访问管理策略。
4.2 实例封闭
将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程在访问数据时总能持有正确的锁。
被封闭对象一定不能够超出它们既定的作用域。对象可以封闭在一个类的实例中(例如作为类的一个私有成员),或者封闭在某个作用域内(例如作为一个局部变量),再或者封闭在一个线程内。
程序清单4-2说明了如何通过封闭和加锁机制使一个类成为线程安全的。
4-2 通过封闭机制来确保线程安全
public class PersonSet{
private final Set<Person> mySet = new HashSet<>();
public synchronized void addPerson(Person p){
mySet.add(p);
}
public synchronized boolean containsPerson(Person p){
return mySet.contains(p);
}
}
实例封闭是构建线程安全类的一个最简单方式。Java类库中还有很多线程封闭的实例,最典型的是一些将非线程安全的类转化为线程安全类的包装器类。例如(Collections.synchronizedList(List<T> list))。
4.2.1 Java 监视器模式
从线程封闭原则及其逻辑推论可以得出Java 监视器模式。遵循Java 监视器模式的对象会把对象的所有可变状态封装起来,并由自己的内置锁来保护。(例如Vector 和 HashTable)
程序清单4-3 通过一个私有锁来保护状态
public class PivateLock{
private final Object myLock = new Object();
void someMethod(){
synchronized(myLock){
}
}
}
使用私有的锁对象而不是对象的内置锁有许多优点。私有的锁对象可以将锁对象封装起来,使客户代码无法得到锁,但客户代码可以通过公有方法来访问锁,以便参与到它的同步策略中。
网友评论