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

修改原始的类

要在已有的线程安全类中添加一个新的原子操作,最安全的方法是修改原始的类。

不足之处:这通常无法做到,因为可能无法访问或修改类的源代码。

扩展类机制

如果在设计这个线程安全类时考虑了可扩展性,那么可以通过继承来添加原子操作。

比如以下代码中的 BetterVector 扩展了 Vector 类,并添加了一个新的同步方法 putIfAbsent:

public class BetterVector<E> extends Vector<E> {
    public synchronized boolean putIfAbsent(E e) {
        boolean absent = !contains(e);
        if (absent)
            add(e);
        return absent;
    }
}

不足之处:如果父类改变了同步策略并选择了不同的锁来保护它的状态变量,那么子类会被破坏。

客户端加锁机制

扩展类的功能,但并不是扩展类本身,而是将扩展代码放入一个“辅助类”中。

如下所示:

public class ListHelper<E> {
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());
    ...
    public boolean putIfAbsent(E e) {
        synchronized(list) {
            boolean absent = !contains(e);
            if (absent)
                add(e);
            return absent;
        }
    }
}

不足之处:客户端加锁机制与扩展类机制一样,将派生类的行为与基类的实现耦合在了一起。如果基类改变了同步策略并选择了不同的锁来保护它的状态变量,那么“辅助类”会被破坏。

组合

public class ImprovedList<E> implements List<E> {
    private final List<E> list;
    
    public ImprovedList(List<E> list) {
        this.list = list;
    }
    
    public synchronized putIfAbsent(E e) {
        boolean absent = !list.contains(e);
        if (absent)
            list.add(e);
        return absent;
    }
    
    public synchronized void clear() { list.clear(); }
    ...
} 

ImprovedList 通过自身的内置锁增加了一层额外的加锁。它并不关心底层的 List 是否是线程安全的,即使 List 不是线程安全的或者修改了它的加锁实现,ImprovedList 也会提供一致的加锁机制来实现线程安全性。

最后更新于