关于java:BlockingQueue-ArrayBlockingQueue

6次阅读

共计 2245 个字符,预计需要花费 6 分钟才能阅读完成。

ArrayBlockingQueue 相对来说就比较简单了。

ArrayBlockingQueue 是基于数组的阻塞队列,创立的时候须要指定容量,也就是说 ArrayBlockingQueue 是有界队列。

ArrayBlockingQueue# 次要属性

items: 也就是 ArrayBlockingQueue 的底层数据结构

final Object[] items;

takeIndex: 下次出队列的地位,包含 take, poll, peek or remove 等操作。

putIndex: 下次入队列的地位,包含 put, offer, or add 等操作。

count: 队列理论长度。

lock:ReentrantLock,出、入队列的时候都须要上锁。

notEmpty:lock 的 Condition,帮助获取数据的线程排队。

notFull:lock 的 Condition,帮助退出队列的线程排队。

构造方法

采纳非偏心锁创立容量为 capacity 的队列:

public ArrayBlockingQueue(int capacity) {this(capacity, false);
    }

创立容量为 capacity 的队列,fair 参数指定应用偏心锁或非偏心锁:

  public ArrayBlockingQueue(int capacity, boolean fair) {if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();}

创立一个非空的队列,如果初始化汇合容量超过了指定的队列容量则抛出异样,初始化数据的过程中统计队列理论容量 count、以及 putIndex:

public ArrayBlockingQueue(int capacity, boolean fair,
                              Collection<? extends E> c) {this(capacity, fair);

        final ReentrantLock lock = this.lock;
        lock.lock(); // Lock only for visibility, not mutual exclusion
        try {
            int i = 0;
            try {for (E e : c) {checkNotNull(e);
                    items[i++] = e;
                }
            } catch (ArrayIndexOutOfBoundsException ex) {throw new IllegalArgumentException();
            }
            count = i;
            putIndex = (i == capacity) ? 0 : i;
        } finally {lock.unlock();
        }
    }

入队和出队

与 LinkedBlockingQueue 相似,ArrayBlockingQueue 也提供了两类出队、入队办法。

阻塞办法:put,take。
非阻塞办法:add、offer、poll, peek,remove。

阻塞办法 put 在队列满的时候通过 notFull、take 在队列空的时候通过 notEmpty 阻塞以后线程,直到条件满足再唤醒返回。

非阻塞的入队办法在队列未满是实现入队返回 true、队列满的话立刻返回 false。非阻塞的出队办法在队列空的时候立刻返回 null。

加锁、阻塞、唤醒形式与 LinkedBlockingQueue 大同小异,所以代码就不贴出了。

不过 ArrayBlockingQueue 的入队和出队采纳了一个比拟奇妙的算法:putIndex、takeIndex、count 初始化为 0,每入队一个元素则 putIndex++、count++,putIndex 达到队列容量 item.length 后再从 0 开始。takeIndex 的操作逻辑相似,每出队一个元素则 takeIndex++、count–,takeIndex 达到队列容量后再从 0 开始。

每次入队的时候都会查看队列容量是否容许以后元素入队,这样就能确保 putIndex、takeIndex 始终保持在一个正确的地位,他们两个就像是在一段长度无限的笔挺公路上始终同向、重复循环行驶的小汽车,在 count 的协调下他们两个永远不会相遇。

区别

简略说一下 SynchronousQueue、LinkedBlockingQueue 和 ArrayBlockingQueue 的不言而喻的区别或者说各自的特点,不肯定全面:

  1. 首先他们都是 BlockingQueue,是线程平安的,多线程环境下能够放心大胆应用
  2. SynchronousQueue 是无界队列,队列中保留的是生产者生产的数据、或者是消费者的获取数据的申请,只提供阻塞办法(底层都是通过 transfer 实现的)
  3. LinkedBlockingQueue 的底层是列表构造,能够是有界的、也能够是无界的,队列中只存储生产者的数据。提供阻塞和非阻塞两种入队、出队操作,通过可重入锁的 Condition 来阻塞线程
  4. ArrayBlockingQueue 的底层是数组,是有界队列,队列中只存储生产者的数据。提供阻塞和非阻塞两种入队、出队操作,通过可重入锁的 Condition 来阻塞线程

小结

三种 BlockingQueue 的源码剖析结束,接下来能够开始学习线程池 ThreadPoolExecutor 的相干内容了。

Thanks a lot!

上一篇 BlockingQueue – LinkedBlockingQueue

正文完
 0