本章介绍如何设计线程安全的类
设计线程安全的类
在设计一个线程安全的类的过程中,需要包含以下三个基本要素:
1.找出构成对象状态的所有变量
2.找出约束状态变量的不变性条件
3.建立对象状态的并发访问管理策略。
基于java监视器模式的线程安全计数器
public final class Counter {
private long value = 0;
public synchronized long get(){
return value;
}
public synchronized long increment(){
return ++value;
}
}
通过封闭机制来确保线程安全
public class PersonSet {
private final Set<Person> mySet = new HashSet<>();
public synchronized void addPerson(Person p){
mySet.add(p);
}
public synchronized boolean containPerson(Person p){
return mySet.contains(p);
}
class Person {
}}
实例封闭是构建线程安全的一个最简单方式,它使得在锁策略的选择上拥有了更多的灵活性。
在java平台类库终还有很多线程封闭的实例,其中有些类的唯一用途就是将非线程安全的类转化成线程安全的类,一些基本的容器类并非线程安全的,例如ArrayList和HashMap,但是类库提供了包装器工厂方法,使得这些非线程安全的类可以在多线程环境中安全地使用。这些工厂方法通过装饰器模式,将容器类封装在一个同步的包装器对象中,而包装器对象拥有对底层容器唯一引用,那么它是线程安全的。
基于监视器模式的车辆追踪:
public class MutablePoint {
public int x;
public int y;
public MutablePoint(MutablePoint loc) {
this.x = loc.x;
this.y = loc.y;
}
public MutablePoint(){
this.x = 0;
this.y = 0;
}
}
public class MonitorVehicleTracker {
private final Map<String, MutablePoint> locations;
public MonitorVehicleTracker(Map<String, MutablePoint> locations){
this.locations = deepCopy(locations);
}
private Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> locations) {
Map<String, MutablePoint> result = new HashMap<>();
for(String id : locations.keySet()){
result.put(id, new MutablePoint(locations.get(id)));
}
return Collections.unmodifiableMap(result);
}
public synchronized Map<String, MutablePoint> getLocations(){
return deepCopy(this.locations);
}
public synchronized MutablePoint getLocations(String id){
MutablePoint loc = locations.get(id);
return loc == null ? null : new MutablePoint(loc);
}
public synchronized void setLocations(String id,int x,int y) throws Exception{
MutablePoint loc = locations.get(id);
if(loc == null){
throw new Exception("No such Id : "+id);
}
loc.x = x;
loc.y = y;
}
}
虽然追踪器类是线程安全的,但是车辆容器非常大的情况下将极大地降低性能。
改造成基于委托的车辆追踪器
public class DelegatingVehicleTracker {
private final ConcurrentMap<String, Point> locations;
private final Map<String , Point> unModifiableMap;
public DelegatingVehicleTracker(Map<String , Point> points){
this.locations = new ConcurrentHashMap<String,Point>(points);
this.unModifiableMap = Collections.unmodifiableMap(locations);
}
public Map<String, Point> getLocations(){
return unModifiableMap;
}
public Point getLocation(String id){
return locations.get(id);
}
public void setLocation(String id,int x,int y){
if(locations.replace(id, new Point(x, y)) == null){
throw new IllegalArgumentException("Invalid vehicle name : "+id);
}
}
/**
* 不可变point
* @author c_dingxuehua-001
*
*/
class Point {
public final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}