UP | HOME

对象组合

Table of Contents

设计线程安全的类 

  1. 确定组成 对象状态变量
  2. 确定 约束对象状态不变式
  3. 建立 并发访问对象状态规则

后置条件

某些变量的取值是有限制范围的, 改变状态变量之后需要 检查改变后的状态 是否合法, 需要额外同步

前置条件

满足一定的条件 操作才能继续进行:

  • wait/notfiy
  • blocking queue
  • semaphore

对象限制

  1. 对象限制在 范围内:作为 类的私有成员
  2. 对象限制在 方法 内部:作为 方法的局部变量
  3. 对象限制在 线程 范围内:只能在 特定线程中访问该对象

monitor模式

public class PrivateLock {
    private final Object myLock = new Object();
    @GuardedBy("myLock") Widget widget;
    void someMethod() {
        synchronized(myLock) {
            // Access or modify the state of widget
        }
    }
}
     使用一个 额外对象加锁 比使用java内置锁更灵活

委托线程安全

  • 如果类只包含 一个状态变量
    • 那么类是否是线程安全的, 取决于 该状态变量是否是线程安全
  • 如果类包含 多个状态变量
    • 如果类中的多个状态变量之间是 相互独立 的, 那么线程安全的责任仍可以 委托给状态变量
    • 如果类中的多个状态变量 参与不变式 ,那需要 额外的同步

对现有类添加线程安全

继承现有类

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

如果 父类修改 了,就可能 破坏子类的同步性

   比如contains的含义变化了 

客户端加锁 

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

客户端加锁更糟糕,因为 客户端加锁的策略 很可能和 被加锁的类自身的锁管理策略违背

对象组合

@ThreadSafe
public class ImprovedList<T> implements List<T> {
    private final List<T> list;
    public ImprovedList(List<T> list) { this.list = list; }
    public synchronized boolean putIfAbsent(T x) {
        boolean contains = list.contains(x);
        if (contains)
            list.add(x);
        return !contains;
    }
    public synchronized void clear() { list.clear(); }
    // ... similarly delegate other List methods
}

继承父类,把父类对象放进子类的一个 final instance, 使用 子类的内置锁 进行同步

Next:基础模块

Previous:对象分享

Up:目录