ArrayBlockingQueue阻塞队列学习总结

编程入门 行业动态 更新时间:2024-10-06 22:30:33

ArrayBlockingQueue阻塞<a href=https://www.elefans.com/category/jswz/34/1771257.html style=队列学习总结"/>

ArrayBlockingQueue阻塞队列学习总结

文章目录

  • 前言
  • 一、ArrayBlockingQueue构造函数初始化数据
  • 二、add、put、poll、peek、take、offer、remove等方法调用
  • 三、Itrs类迭代器的使用
  • 总结


前言

        ArrayBlockingQueue是一个基于数组的阻塞队列实现,在多线程环境下,自动管理了多线间的自动等待于唤醒功能,从而使得程序员可以忽略这些细节,关注更高级的功能。


一、ArrayBlockingQueue构造函数初始化数据

        初始构造函数内定义容量大小capacity,是否采用公平锁fair,以及源集合数据。自定义数组items,赋予容量大小长度并将集合数据导入items数组,定义putIndex为下一次插入队列的起点,若队列已满则为0。notEmpty和notFull分别为take和put操作的两个阻塞条件。

二、add、put、poll、peek、take、offer、remove等方法调用

1.add方法

该方法直接调offer,如果队列已满,直接throw new IllegalStateException("Queue full")

public boolean add(E e) {return super.add(e);}

2.put方法

加可中断锁并且在队列满的时候利用方法notFull.await造成线程阻塞,未满则调用enqueue(e)方法将元素插入,并且,激活一个notEmpty,即take阻塞条件的线程。

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) {// 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();}

3.poll方法

加锁并且在队列数量为0时返回null,否则利用方法dequeue获取并移除此队列的头元素,并且,激活一个notFull,即put阻塞条件的线程。

 public E poll() {final ReentrantLock lock = this.lock;lock.lock();try {return (count == 0) ? null : dequeue();} finally {lock.unlock();}}
private E dequeue() {// assert lock.getHoldCount() == 1;// assert items[takeIndex] != null;final Object[] items = this.items;@SuppressWarnings("unchecked")E x = (E) items[takeIndex];items[takeIndex] = null;if (++takeIndex == items.length)takeIndex = 0;count--;if (itrs != null)itrs.elementDequeued();notFull.signal();return x;}

4.peek方法

直接返回当前队列的头元素,但不删除

public E peek() {final ReentrantLock lock = this.lock;lock.lock();try {return itemAt(takeIndex); // null when queue is empty} finally {lock.unlock();}}

5.take方法

加可中断锁并且在队列空的时候利用方法notEmpty.await造成线程阻塞,未空则调用enqueue(e)方法将元素拿走,并且,激活一个notFull,即put阻塞条件的线程

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

6.offer方法

只有集合元素时加常规锁并且在队列满的时候返回false,未满则调用enqueue(e)方法将元素插入,并且,激活一个notEmpty,即take阻塞条件的线程;不仅有集合元素还有时间参数时加可中断锁,并且在队列满的时候进入线程等待,等待时间到后激活线程如果依旧是满则返回false,未满则调用enqueue(e)方法将元素插入,并且,激活一个notEmpty,即take阻塞条件的线程。

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();}}
public boolean offer(E e, long timeout, TimeUnit unit)throws InterruptedException {checkNotNull(e);long nanos = unit.toNanos(timeout);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == items.length) {if (nanos <= 0)return false;nanos = notFull.awaitNanos(nanos);}enqueue(e);return true;} finally {lock.unlock();}}

7.remove方法

删除元素,do-while循环找到元素并在remveAt方法中删除该索引所对应元素。在removeAt方法中,如果删除元素时队列头元素则直接删除,否则将元素删除后所有往后索引及所对应元素前移。

public boolean remove(Object o) {if (o == null) return false;final Object[] items = this.items;final ReentrantLock lock = this.lock;lock.lock();try {if (count > 0) {final int putIndex = this.putIndex;int i = takeIndex;do {if (o.equals(items[i])) {removeAt(i);return true;}if (++i == items.length)i = 0;} while (i != putIndex);}return false;} finally {lock.unlock();}}
void removeAt(final int removeIndex) {// assert lock.getHoldCount() == 1;// assert items[removeIndex] != null;// assert removeIndex >= 0 && removeIndex < items.length;final Object[] items = this.items;if (removeIndex == takeIndex) {// removing front item; just advanceitems[takeIndex] = null;if (++takeIndex == items.length)takeIndex = 0;count--;if (itrs != null)itrs.elementDequeued();} else {// an "interior" remove// slide over all others up through putIndex.final int putIndex = this.putIndex;for (int i = removeIndex;;) {int next = i + 1;if (next == items.length)next = 0;if (next != putIndex) {items[i] = items[next];i = next;} else {items[i] = null;this.putIndex = i;break;}}count--;if (itrs != null)itrs.removedAt(removeIndex);}notFull.signal();}

三、Itrs类迭代器的使用

 if (itrs != null)itrs.elementDequeued();
if (itrs != null)itrs.removedAt(removeIndex);

        在 ArrayBlockingQueue 中使用 Itrs 维护这一个 Itr 链表,用于在一个队列下的多个 Itr 迭代器中共享队列元素,保证多个迭代器中的元素数据的一致性。


总结

        阻塞队列在并发状态下能满足线程的安全性,并且在对队列进行操作时有自己的阻塞以及开启线程处理,替开发人员考虑了队列满或空所造成的一些异常判断,在生产消费者模式的开发中,非常好用。

更多推荐

ArrayBlockingQueue阻塞队列学习总结

本文发布于:2024-02-13 20:00:20,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1760193.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:队列   ArrayBlockingQueue

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!