首页 > 编程 > Java > 正文

Java源码解析阻塞队列ArrayBlockingQueue常用方法

2019-11-26 09:22:13
字体:
来源:转载
供稿:网友

本文基于jdk1.8进行分析

ArrayBlockingQueue的功能简介参考https://www.VeVB.COm/article/154211.htm

首先看一下ArrayBlockingQueue的成员变量。如下图。最主要的成员变量是items,它是一个Object类型的数组用于保存阻塞队列中的元素。其次是takeIndex,putIndex,count,分别表示了从队列获取元素的位置,往队列里放元素的位置和队列中元素的个数。然后是lock,notEmpty和notFull三个和锁相关的成员变量。lock是一个可重入锁,而notEmpty和notFull是和lock绑定的2个Condition。对可重入锁不是很了解的同学,可以参考这篇文章https://www.VeVB.COm/article/154207.htm。对可重入锁的理解,是理解ArrayBlockingQueue的基础。也可以这么说,理解了可重入锁,那么在理解ArrayBlockingQueue就很顺利了。

  /** The queued items **/  final Object[] items;  /** items index for next take, poll, peek or remove **/  int takeIndex;  /** items index for next put, offer, or add **/  int putIndex;  /** Number of elements in the queue **/  int count;  /**   * Concurrency control uses the classic two-condition algorithm   * found in any textbook.   **/  /** Main lock guarding all access **/  final ReentrantLock lock;  /** Condition for waiting takes **/  private final Condition notEmpty;  /** Condition for waiting puts **/  private final Condition notFull;  /**   * Shared state for currently active iterators, or null if there   * are known not to be any. Allows queue operations to update   * iterator state.   **/  transient Itrs itrs = null;

接下来介绍ArrayBlockingQueue的主要方法。首先是入队方法。ArrayBlockingQueue的入队方法有好几个,功能略有差异,下面我们逐一介绍各个入队方法。首先看一下put方法,如下图。put方法的功能是,往队列尾部插入指定元素,如果队列已满,那么就等待可用空间。方法的实现过程是,首先判断元素是否非空。然后,进行加锁,加锁后判断队列是否已满。如果已满,则等待不满条件。当被唤醒后,进行入队操作。入队方法中,会唤醒在notEmpty条件上等待的线程。

  /**   * Inserts the specified element at the tail of this queue, waiting   * for space to become available if the queue is full.   * @throws InterruptedException {@inheritDoc}   * @throws NullPointerException {@inheritDoc}   **/  public void put(E e) throws InterruptedException {    checkNotNull(e);    final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try {      while (count == items.length)        notFull.await();      enqueue(e);    } finally {      lock.unlock();    }  }  /**   * Inserts element at current put position, advances, and signals.   * Call only when holding lock.   **/  private void enqueue(E x) {    // assert lock.getHoldCount() == 1;    // assert items[putIndex] == null;    final Object[] items = this.items;    items[putIndex] = x;    if (++putIndex == items.length)      putIndex = 0;    count++;    notEmpty.signal();  }

另一个入队方法是offer,代码如下。这个方法与add方法的区别是,offer方法是立刻返回的,它并不像add方法那样,当队列满时会一直等待。

  /**   * Inserts the specified element at the tail of this queue if it is   * possible to do so immediately without exceeding the queue's capacity,   * returning {@code true} upon success and {@code false} if this queue   * is full. This method is generally preferable to method {@link #add},   * which can fail to insert an element only by throwing an exception.   * @throws NullPointerException if the specified element is null   **/  public boolean offer(E e) {    checkNotNull(e);    final ReentrantLock lock = this.lock;    lock.lock();    try {      if (count == items.length)        return false;      else {        enqueue(e);        return true;      }    } finally {      lock.unlock();    }  }

接下来看一下出队方法take,代码如下。首先对可重入锁加锁,然后判断元素个数是否为0.如果为0,则等待不空条件,否则进行出队操作。

  public E take() throws InterruptedException {    final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try {      while (count == 0)        notEmpty.await();      return dequeue();    } finally {      lock.unlock();    }  }

ArrayListBlockingqueue中还有其他相关方法,这里就不一一介绍了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对武林网的支持。如果你想了解更多相关内容请查看下面相关链接

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表