chapter04_对象的组合_4_在现有的线程安全类中添加功能

  • 很多情况下应该重用现有的类, 添加自定义的功能, 此时需要在__不破坏线程安全性__的情况下添加新的操作

    (1) 方法一: 直接修改原始的类

    优点: 同步策略仍然处于同一个源代码文件中, 更容易理解和维护

    缺点: 常常无法修改源代码

    (2) 方法二: 扩展这个类

    同步策略分布到了各个文件中, 并且要确定的得知基类的同步策略

    示例

      @ThreadSafe
      public class BetterVector<E> extends Vector<E> {
    
          // 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<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;
          }
      }
    

    正确示例

      @ThreadSafe
      class GoodListHelper<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;
              }
          }
      }
    

    正确示例和错误示例的区别在于使用锁的不同, 深入Collections.synchronizedList的源码, 会发现它使用的锁就是Collections.synchronizedList对象本身, 所以辅助类中也要使用Collections.synchronizedList本身作为锁

    和方法二一样, 客户端加锁方式也存在同步策略分布在各个类中的问题, 这样当底层源码的同步策略改变时可能会不稳。

    (4) 方法四: 组合

    使用Java监视器模式, 对内部的对象完全由类本身提供的锁保护, 不管底层的类是否线程安全

    示例

      @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;
          }
    
          // 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<T> iterator() {
              return list.iterator();
          }
    
          public Object[] toArray() {
              return list.toArray();
          }
    
          public <T> 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<T> listIterator() {
              return list.listIterator();
          }
    
          public ListIterator<T> listIterator(int index) {
              return list.listIterator(index);
          }
    
          public List<T> subList(int fromIndex, int toIndex) {
              return list.subList(fromIndex, toIndex);
          }
      }
    

    所有需要同步的方法都使用ImprovedList本身的锁, 而不必在意封装对象的同步策略

  • 同步策略应该文档化

    定义好

    (1) 哪些变量为volatile

    (2) 哪些变量用锁保护

    (3) 哪些变量必须不可变或者线程封闭

    (4) 哪些操作必须是原子操作

    等……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值