首页 > 代码库 > 第四章:对象的组合——java并发编程实战
第四章:对象的组合——java并发编程实战
一、设计线程安全的类
- 找出构造对象状态的所有变量(若变量为引用类型,还包括引用对象中的域)
- 约束状态变量的不变性条件
- 建立对象状态的并发访问管理策略(规定了如何维护线程安全性)
1、收集同步需求(找出复合操作、多个变量遵循原子性的操作等)
2、依赖状态的操作(找出操作是否基于先验条件,例:取出当队列不为空)
3、状态的所有权(对象被哪些线程所有,哪些线程可以操作对象)
二、实例封闭
将数据封装在对象内部,可以将数据的访问限制在对象的方法上,确保简单正确的持有锁。(因为无需观察整个程序,只需检查当前类)
Java提供包装器对ArrayList、HashMap等容器对象提供线程安全保护
1、Java监视器模式:把对象的所有可变状态封装起来,并使用对象的内置锁保护
使用私有锁而不是内置锁的优点:(private final Object myLock = new Object();)
- 私有锁可以将锁封装起来,客户代码无法得到锁
- 客户可以通过公有方法来访问锁,以便参与到同步策略中去。
2、实例:基于监视器模式的车辆追踪
MutablePoint不一定是线程安全的,但该类一定是线程安全的,因为它包含的Map对象与Map中的Point对象都未曾发布,并且满足实例封闭。
三、线程安全性的委托
通过多个线程安全的类组成的类不一定是线程安全的
委托:通过委托类的线程安全性判断被委托类的线程安全性
1、委托给单个线程安全状态变量可以保证线程安全性
2、委托给多个相互独立的线程安全状态变量可以保证线程安全性
3、如果类包含多个线程安全状态变量的符合操作,则无法保证线程安全性,可以通过加锁机制保证
4、发布:如果一个状态变量是线程安全的,并且没有不变性条件约束它(例:大于0),在变量操作上没有不允许的状态转换,则可以安全发布
5、安全发布底层状态的线程安全类
1 @ThreadSafe 2 public class PublishingVehicleTracker { 3 private final Map<String, SafePoint> locations; 4 private final Map<String, SafePoint> unmodifiableMap; 5 6 public PublishingVehicleTracker(Map<String, SafePoint> locations) { 7 this.locations = new ConcurrentHashMap<String, SafePoint>(locations); 8 this.unmodifiableMap = Collections.unmodifiableMap(this.locations); 9 } 10 11 public Map<String, SafePoint> getLocations() { 12 return unmodifiableMap; 13 } 14 15 public SafePoint getLocation(String id) { 16 return locations.get(id); 17 } 18 19 public void setLocation(String id, int x, int y) { 20 if (!locations.containsKey(id)) 21 throw new IllegalArgumentException("invalid vehicle name: " + id); 22 locations.get(id).set(x, y); 23 } 24 }
四、现有的线程安全类中添加功能
例:在Vector中添加”若没有则添加“功能,可以使用拓展的办法,BetterVector继承至Vector并对该符合操作通过同步机制增加原子性
1、客户端加锁机制
使用某个对象的代码时必须使用该对象本身用于保护其状态的锁,不推荐(同步的实现被分到两个不相关的类中)
当没有使用同一个锁,不足以提供线程安全保护:
2、组合
ImprovedList将List的操作委托给底层的list实例来操作,并通过自身的内置锁增加一层额外的加锁,同时添加了新的同步方法。
五、将同步策略文档化
第四章:对象的组合——java并发编程实战