本章介绍如何设计线程安全的类
设计线程安全的类
在设计一个线程安全的类的过程中,需要包含以下三个基本要素:
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; } }