4. BlockingQueue源码解析BlockingQueue的5种子类实现方式大同小异,这次就以最常用的ArrayBlockingQueue做源码解析 。
4.1 ArrayBlockingQueue类属性先看一下ArrayBlockingQueue类里面有哪些属性:
// 用来存放数据的数组final Object[] items;// 下次取数据的数组下标位置int takeIndex;// 下次放数据的数组下标位置int putIndex;// 当前已有元素的个数int count;// 独占锁,用来保证存取数据安全final ReentrantLock lock;// 取数据的条件private final Condition notEmpty;// 放数据的条件private final Condition notFull;
ArrayBlockingQueue中4组存取数据的方法实现也是大同小异,本次以put和take方法进行解析 。
4.2 put方法源码解析
文章插图
无论是放数据还是取数据都是从队头开始,逐渐往队尾移动 。
// 放数据,如果队列已满,就一直阻塞,直到有其他线程从队列中取走数据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();}}// 实际往队列添加数据的方法private void enqueue(E x) {// 获取数组final Object[] items = this.items;// putIndex 表示本次插入的位置items[putIndex] = x;// ++putIndex 计算下次插入的位置// 如果本次插入的位置,正好是队尾,下次插入就从 0 开始if (++putIndex == items.length)putIndex = 0;// 元素数量加一count++;// 唤醒因为队列空等待的线程notEmpty.signal();}
源码中有个有意思的设计,添加元素的时候如果已经到了队尾,下次就从队头开始添加,相当于做成了一个循环队列 。像下面这样:
文章插图
4.3 take方法源码
// 取数据,如果队列为空,就一直阻塞,直到有其他线程往队列中放数据public E take() throws InterruptedException {final ReentrantLock lock = this.lock;// 加锁,加可中断的锁lock.lockInterruptibly();try {// 如果队列为空,就一直阻塞,直到被唤醒while (count == 0)notEmpty.await();// 如果队列不为空,就从队列取数据return dequeue();} finally {// 结束后,别忘了释放锁lock.unlock();}}// 实际从队列取数据的方法private E dequeue() {// 获取数组final Object[] items = this.items;// takeIndex 表示本次取数据的位置,是上一次取数据时计算好的E x = (E) items[takeIndex];// 取完之后,就把队列该位置的元素删除items[takeIndex] = null;// ++takeIndex 计算下次取数据的位置// 如果本次取数据的位置,正好是队尾,下次就从 0 开始取数据if (++takeIndex == items.length)takeIndex = 0;// 元素数量减一count--;if (itrs != null)itrs.elementDequeued();// 唤醒被队列满所阻塞的线程notFull.signal();return x;}
4.4 总结- ArrayBlockingQueue基于数组实现的阻塞队列,创建队列时需指定容量大小,是有界队列 。
- ArrayBlockingQueue底层采用循环队列的形式,保证数组位置可以重复使用 。
- ArrayBlockingQueue存取都采用ReentrantLock加锁,保证线程安全,在多线程环境下也可以放心使用 。
- 使用ArrayBlockingQueue的时候,预估好队列长度,保证生产者和消费者速率相匹配 。
- 4 Java注解:一个真实的Elasticsearch案例
- 原生JavaScript
- 3 Java注解:一个真实Elasticsearch案例
- JavaWeb完整案例详细步骤
- redis bitmap数据结构之java对等操作
- 公务员工资那么低怎么养家 为什么还有很多人考
- Java工具类 利用Hutool-实现验证码校验
- JavaFx 使用字体图标记录
- 含具体案例 Java8新特性之Stream流
- Java学习之路:流程控制