java+arrayblockquene_并发队列之ArrayBlockingQueue

上一篇我们说了并发队列中的LinkedBlockingQueue队列,这次我们看看ArrayBlockingQueue,看看名字,我们想象一下LinkedList和ArrayList的区别,我们可以知道ArrayBlockingQueue底层肯定是基于数组实现的,这是一个有界数组;

ArrayBlockingQueue其中的组成部分和LinkedBlockingQueue及其相似,也是有两个条件变量,维护阻塞队列,实现了生产消费者模式;

一.简单认识ArrayBlockingQueue

先看看几个常用属性:

//数组用于存放队列元素

finalObject[] items;//出队索引

inttakeIndex;//入队索引

intputIndex;//队列中元素数量

intcount;//独占锁

finalReentrantLock lock;//如果数组中为空,还有线程取数据,就丢到这个条件变量中来阻塞

private finalCondition notEmpty;//队列满了,还有线程往数组中添加数据,就把线程丢到这里来阻塞

private final Condition notFull;

由于这是一个有界的数组,我们再看看构造器:

//指定容量,默认是非公平策略

public ArrayBlockingQueue(intcapacity) {this(capacity, false);

}//指定容量和独占锁的策略

public ArrayBlockingQueue(int capacity, booleanfair) {if (capacity <= 0)throw newIllegalArgumentException();this.items = newObject[capacity];

lock= newReentrantLock(fair);

notEmpty=lock.newCondition();

notFull=lock.newCondition();

}//可以指定容量,锁的策略,还有初始化数据

public ArrayBlockingQueue(int capacity, booleanfair,

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 newIllegalArgumentException();

}

count=i;

putIndex= (i == capacity) ? 0: i;

}finally{

lock.unlock();

}

}

二.offer方法

向队列尾部添加一个元素,添加成功就返回true,队列满了就丢掉当前元素直接返回false,方法不阻塞;

public booleanoffer(E e) {//非空检验

checkNotNull(e);final ReentrantLock lock = this.lock;

lock.lock();try{//如果数组中实际数量和最大容量相等,添加失败,返回false

if (count ==items.length)return false;else{//添加成功,方法实现在下面

enqueue(e);return true;

}

}finally{//释放锁

lock.unlock();

}

}private voidenqueue(E x) {//拿到数组

final Object[] items = this.items;//在putIndex这个位置放入数据x,然后把putIndex加一,说明这个参数表示的是下一个数据要放入的位置的索引

items[putIndex] =x;//这里putIndex是先加一然后再比较是否相等,比如这里数组的最大容量是5,那么索引的最大值应该是4,而如果putIndex等于5了,说明数组//越界了,加把这个索引重置为0

if (++putIndex ==items.length)

putIndex= 0;

count++;//添加完成之后,说明了数组中有数据了,这里会唤醒之前因为去数组中取数据而阻塞的线程

notEmpty.signal();

}

三.put方法

向队列尾部插入一个元素,队列有空闲就插入成功返回true,队列满了就阻塞当前线程到notFull的条件队列中,等有空闲之后就会被唤醒;阻塞过程中对中断会有响应的;

public void put(E e) throwsInterruptedException {//非空检查

checkNotNull(e);final ReentrantLock lock = this.lock;//注意该锁的获取方式

lock.lockInterruptibly();try{//如果线程满了,就把当前线程放到notFull条件变量的阻塞队列中

while (count ==items.length)

notFull.await();//没有满,就添加数据

enqueue(e);

}finally{//释放锁

lock.unlock();

}

}

四.poll方法

头部获取并移除一个元素,如果队列为空,就返回null,方法不阻塞;

publicE poll() {final ReentrantLock lock = this.lock;

lock.lock();try{//如果队列为空,就返回null//如果队列不为空,就调用dequeue方法获取并删除队列头部的元素

return (count == 0) ? null: dequeue();

}finally{

lock.unlock();

}

}privateE dequeue() {//获取数组

final Object[] items = this.items;

@SuppressWarnings("unchecked")//获取takeIndex位置的元素,最后会将这个返回

E x =(E) items[takeIndex];//然后将takeInde位置置为空

items[takeIndex] = null;//如果takeIndex已经是数组的最后一个位置了,就将takeIndex重置为0

if (++takeIndex ==items.length)

takeIndex= 0;//实际数量减一

count--;if (itrs != null)

itrs.elementDequeued();//唤醒notFull中线程

notFull.signal();returnx;

}

五.take方法

获取并删除当前队列头部的元素,如果队列为空当前线程阻塞直到被唤醒,对中断有响应;

public E take() throwsInterruptedException {final ReentrantLock lock = this.lock;//可中断的方式获取锁

lock.lockInterruptibly();try{//如果数组为空,此时就唤醒notEmpty中条件队列里的线程

while (count == 0)

notEmpty.await();//获取并删除头节点

returndequeue();

}finally{

lock.unlock();

}

}

六.peek方法

只是获取头部元素,不删除,如果队列为空就返回null,这个方法是线程不阻塞的

publicE peek() {final ReentrantLock lock = this.lock;

lock.lock();try{return itemAt(takeIndex); //null when queue is empty

} finally{

lock.unlock();

}

}//获取到数组中索引为takeIndex中的数据

@SuppressWarnings("unchecked")final E itemAt(inti) {return(E) items[i];

}

七.总结

理解了上一篇博客中说的LinkedBlockingQueue,那么再看这一篇其实太容易了,就是操作数组嘛!用下面这个图表示:

f6ba4ec9a54d90b619f3635fa03ef934.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值