Java并发编程实战4章

第4章主要介绍如何构造线程安全类。

在设计线程安全类的过程中,需要包含以下三个基本要素:

构造线程安全类常采用的技术如下:

实例封闭

当一个对象被封装到另一个对象中时,能够访问被封装对象的所有代码路径都是已知的。与对象可以由整个程序访问的情况相比,更易于对代码进行分析。通过将封闭机 制与合适的加锁策略结合起来,可以确保以线程安全的方式来使用非线程安全的对象。

对象一般可以封闭在三种地方:

在Java平台的类库中有很多线程封闭的示例,比如一些基本的容器类并非线程安全的,例如ArrayList和HashMap,但类库提供了包装器工厂方法,使得这些非线程安全的类可以在多线程环境中安全地使用。

委托

如果一个类是由多个独立且线程安全的状态变量组成,并且在所有的操作中都不包含无效状态转换,那么可以将线程安全性委托给底层的状态变量。

在现有的线程安全类中添加功能:

例子:假设需要一个线程安全的链表,它需要提供一个原子的“若没有则添加(put-if-Absent)”的操作

1.扩展

BetterVector<E> extends Vector<E> { putIfAbsent(E x) {3boolean absent = !contains(x);4if (absent) {5 add(x);6 }7return absent;8 }9 }

这种方法的缺点是:导致了现在的同步策略实现被分布到多个单独维护的源代码文件中,一旦底层的类改变了同步策略并选择了不同的锁来保护它的状态变量,美国空间,那么子类会被破坏,因为在同步策略改变后无法再使用正确的锁来控制对基类状态的并发访问。

2.客户端加锁机制

ListHelper<E> {List<E> list = Collections.synchronizedList(new ArrayList<E>()); 4 … putIfAbsent(E x) { 6synchronized (list) { 7boolean absent = !list.contains(x); 8if (absent) { 9 list.add(x);10 }11return absent;12 }13 }14 15 }

这种方式很脆弱,因为它将类C的加锁代码放到与C完全无关的其他类中,会导致混乱的。

客户端加锁机制与扩展类机制的共同点:将派生类的行为与基类的实现耦合在一起,扩展破坏了实现的封装性,服务器空间,客户端加锁破坏了同步策略的封装性。

3.组合

ImprovedList<E> implements List<E> {List<E> list;ImprovedList(List<E> list) { 6this.list = list; 7 } putIfAbsent(E x) {10boolean contains = list.contains(x);11if (contains) {12 list.add(x);13 }14return !contains;15 } clear() {18 list.clear();19 }}

这里其实使用了Java监视器模式来封装现有的List,并且只要在类中拥有指向底层List的唯一外部引用,就能确保线程安全性。

最后需要将同步策略文档化。

,香港虚拟主机人生的小河,总要流过森林,荒漠,

Java并发编程实战4章

相关文章:

你感兴趣的文章:

标签云: