chapter14_构建自定义的同步工具_3_显式的Condition对象

时间:2019-03-19
本文章向大家介绍chapter14_构建自定义的同步工具_3_显式的Condition对象,主要包括chapter14_构建自定义的同步工具_3_显式的Condition对象使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
  • (1) Condition是一种广义的条件队列

    (2) 在java.util.concurrent.locks包中, Condition是一个接口

      public interface Condition {
    
          void await() throws InterruptedException;
    
          void awaitUninterruptibly();
    
          long awaitNanos(long nanosTimeout) throws InterruptedException;
    
          boolean await(long time, TimeUnit unit) throws InterruptedException;
    
          boolean awaitUntil(Date deadline) throws InterruptedException;
    
          void signal();
    
          void signalAll();
      }
    

    (3) 如果想编写一个带有多个条件谓词的并发对象, 或者想获得更多对条件队列的控制权, 那么就可以考虑用Condition代替原生条件队列

    (4) 一个Condition对象和一个Lock对象关联在一起(就像一个条件队列和一个内置锁关联一样);

    但是一个Lock对象可以关联任意数量的Condition对象(通过Lock的Condition newCondition();方法)

    (5) Condition对象继承了相关的Lock对象的公平性(如果Lock是公平的, 那么线程会按照FIFO从Condition的await中释放)

    (6) wait、notify、notifyAll是Object的方法, 由于Object是所有类的基类, 所以Condition的实现类也有这三个方法. __但是, 使用Condition要用它的await、signal、signalAll方法

  • (1) 示例

      @ThreadSafe
      public class ConditionBoundedBuffer<T> {
    
          private static final int BUFFER_SIZE = 100;
    
          protected final Lock lock = new ReentrantLock();
    
          // CONDITION PREDICATE: notFull (count < items.length)
          private final Condition notFull = lock.newCondition();
    
          // CONDITION PREDICATE: notEmpty (count > 0)
          private final Condition notEmpty = lock.newCondition();
    
          @GuardedBy("lock")
          private final T[] items = (T[]) new Object[BUFFER_SIZE];
    
          @GuardedBy("lock")
          private int tail, head, count;
    
          // BLOCKS-UNTIL: notFull
          public void put(T x) throws InterruptedException {
    
              lock.lock();
    
              try {
                  while (count == items.length) {
                      notFull.await();
                  }
    
                  items[tail] = x;
    
                  if (++tail == items.length) {
                      tail = 0;
                  }
    
                  ++count;
                  notEmpty.signal();
    
              } finally {
    
                  lock.unlock();
              }
          }
    
          // BLOCKS-UNTIL: notEmpty
          public T take() throws InterruptedException {
    
              lock.lock();
    
              try {
                  while (count == 0) {
                      notEmpty.await();
                  }
    
                  T x = items[head];
                  items[head] = null;
    
                  if (++head == items.length) {
                      head = 0;
                  }
    
                  --count;
    
                  notFull.signal();
    
                  return x;
    
              } finally {
    
                  lock.unlock();
              }
          }
      }
    

    (2) 这个示例使用Condition, 优点有两个:

    1. 容易理解: put操作等待的是notFull条件, take操作等待的是notEmpty条件

    2. 使用signal而非signalAll, 效率高:

    之所以敢使用signal, 是因为当前的情境满足了那两个条件(见"2_使用条件队列.md"中的"什么时候可以放心大胆的使用notify"); 而用两个不同的Condition保证了其中一个条件