介绍可以通过对象组合构造一个满足需求的线程安全的类。
笔记来自《java并发编程实战》
监视器模式(实例封闭)
遵循java监视器模式的对象会把对象的所有可变状态都封装起来,并由对象自己的内置锁来保护。如:
public calss PrivateLock {
private final Object myLock = new Object();
Widget widget;
void someMethod() {
synchronized(myLock) {
//do something with widget
}
}
}
线程安全性委托
所谓线程安全性的委托,就是如果类的成员变量都是线程安全的,整个类的线程安全性可以委托给类的成员变量。当然至于委托后,这个对象是不是线程安全的,要“看情况而定”。
当成员变量之间没有任何交互或者不变形条件约束的时候,那么这个类可以表现为线程安全。如:
public class VisualComponet{ private final List<Listener> list = new CopyOnWriteArrayList<Listener>(); public void addListener(Listener listener) { list.add(listener); } }
当状态变量之间存在着某些不变型条件的时候,委托失效,即类不是线程安全的。如:
public class NumberRange { //不变性条件为 lower < upper private final AtomicInteger lower = new AtomicInteger(0); private final AtomicInteger upper = new AtomicInteger(0); public void setLower(int i) { if (i <= upper.get()) { lower.set(i); } } }
在
setLower
方法中,先检查再赋值,并不是原子性的,当然也会出现线程安全性的问题。
在现有线程安全类中添加功能
java类库中有许多有用的基础模块,应该优先选择重用这些现有的类而不是创建新的类。
继承线程安全的类,实现一些附加的操作,如继承vector来“实现不存在就添加”的操作:
public class BetterVector extends Vector { public synchronized boolean putIfAbsent(Object o) { boolean absent = ! contains(o); if (absent) add(x) return absent; } }
利用
Collections.synchronizedList()
实现public class ListHelper { public List<E> list = new Collections.synchronizedList(new ArrayList<>); public boolean putIfAbsent(Object o) { synchronized(list) { boolean absent = ! contains(o); if (absent) add(x) return absent; } } }
这里有个要注意的,
putIfAbsent
获取的锁是list的锁,如果简单粗暴的在putIfAbsent
上加上synchronized,是有问题的,像这样@NotThreadSafe class BadListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public synchronized boolean putIfAbsent(E x) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } }
这里的问题就是,synchronized所对应的锁和对list操作的锁不是同一把,你获取了BadListHelper的锁,但是没有获取list的锁,线程安全问题还是没有解决,别人还是可以在你执行
putIfAbsent
方法时,对list进行修改。使用组合对象
public class ImprovedList<E> implements List<E> { private final List<E> list; public ImprovedList(List<E> list) { this.list = list; } public synchronized boolean putIfAbsent(Object o) { boolean absent = ! contains(o); if (absent) add(x) return absent; } ... }
这里涉及到了Collections.synchronizedList()
和CopyOnWriteArrayList
。关于这两个,看看源码研究研究区别,专门写篇博客。