-
很多情况下应该重用现有的类, 添加自定义的功能, 此时需要在不破坏线程安全性的情况下添加新的操作
(1) 方法一: 直接修改原始的类
优点: 同步策略仍然处于同一个源代码文件中, 更容易理解和维护
缺点: 常常无法修改源代码
(2) 方法二: 扩展这个类
同步策略分布到了各个文件中, 并且要确定的得知基类的同步策略
示例
@ThreadSafe
public class BetterVector extends Vector {
// When extending a serializable class, you should redefine serialVersionUID
static final long serialVersionUID = -3963416950630760754L;
public synchronized boolean putIfAbsent(E x) {
boolean absent = !super.contains(x);
if (absent) {
super.add(x);
}
return absent;
}
}
(3) __方法三: 客户端加锁机制__
扩展类的功能, 但不是扩展类本身, 而是将扩展代码放入__辅助类__中
__客户端加锁__: 对于使用某个对象X的客户端代码, 使用__X本身用于保护其状态的锁__来保护这段客户代码
__所以, 使用客户端加锁方式, 必须从源码中找到X使用的是哪一个锁__
示例
错误示例
@NotThreadSafe
class BadListHelper {
public List list = Collections.synchronizedList(new ArrayList());
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if (absent) {
list.add(x);
}
return absent;
}
}
正确示例
@ThreadSafe
class GoodListHelper {
public List list = Collections.synchronizedList(new ArrayList());
public boolean putIfAbsent(E x) {
synchronized (list) {
boolean absent = !list.contains(x);
if (absent) {
list.add(x);
}
return absent;
}
}
}
正确示例和错误示例的区别在于使用锁的不同, 深入Collections.synchronizedList的源码, 会发现它使用的锁就是Collections.synchronizedList对象本身, 所以辅助类中也要使用Collections.synchronizedList本身作为锁
和方法二一样, 客户端加锁方式也存在同步策略分布在各个类中的问题, 这样当底层源码的同步策略改变时可能会不稳。
(4) __方法四: 组合__
__使用Java监视器模式, 对内部的对象完全由类本身提供的锁保护, 不管底层的类是否线程安全__
示例
@ThreadSafe
public class ImprovedList implements List {
private final List list;
public ImprovedList(List list) {
this.list = list;
}
public synchronized boolean putIfAbsent(T x) {
boolean contains = list.contains(x);
if (contains) {
list.add(x);
}
return !contains;
}
// Plain vanilla delegation for List methods.
// Mutative methods must be synchronized to ensure atomicity of putIfAbsent.
public synchronized boolean addAll(Collection extends T> c) {
return list.addAll(c);
}
public synchronized boolean addAll(int index, Collection extends T> c) {
return list.addAll(index, c);
}
public synchronized boolean removeAll(Collection> c) {
return list.removeAll(c);
}
public synchronized boolean retainAll(Collection> c) {
return list.retainAll(c);
}
public synchronized void clear() {
list.clear();
}
public synchronized boolean add(T e) {
return list.add(e);
}
public synchronized boolean remove(Object o) {
return list.remove(o);
}
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public boolean contains(Object o) {
return list.contains(o);
}
public Iterator iterator() {
return list.iterator();
}
public Object[] toArray() {
return list.toArray();
}
public T[] toArray(T[] a) {
return list.toArray(a);
}
public boolean containsAll(Collection> c) {
return list.containsAll(c);
}
public boolean equals(Object o) {
return list.equals(o);
}
public int hashCode() {
return list.hashCode();
}
public T get(int index) {
return list.get(index);
}
public T set(int index, T element) {
return list.set(index, element);
}
public void add(int index, T element) {
list.add(index, element);
}
public T remove(int index) {
return list.remove(index);
}
public int indexOf(Object o) {
return list.indexOf(o);
}
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
public ListIterator listIterator() {
return list.listIterator();
}
public ListIterator listIterator(int index) {
return list.listIterator(index);
}
public List subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
}
所有需要同步的方法都使用ImprovedList本身的锁, 而不必在意封装对象的同步策略
-
同步策略应该文档化
定义好
(1) 哪些变量为volatile
(2) 哪些变量用锁保护
(3) 哪些变量必须不可变或者线程封闭
(4) 哪些操作必须是原子操作
等……