专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
芋道源码  ·  Hutool中的这些工具类,太实用了! ·  17 小时前  
Java编程精选  ·  看个文章隐私就被窃取了?3·15晚会曝光获客 ... ·  2 天前  
芋道源码  ·  疯传Java界,堪称最强! ·  2 天前  
Java编程精选  ·  Map 只会 ... ·  3 天前  
51好读  ›  专栏  ›  ImportNew

并发队列 – 有界阻塞队列 ArrayBlockingQueue 原理探究

ImportNew  · 公众号  · Java  · 2017-07-17 13:03

正文

(点击 上方公众号 ,可快速关注)


来源:今天你不奋斗明天你就落后,

www.jianshu.com/p/ff116eaad0dd

如有好文章投稿,请点击 → 这里了解详情


一、 前言


上节介绍了无界链表方式的阻塞队列LinkedBlockingQueue,本节来研究下有界使用数组方式实现的阻塞队列ArrayBlockingQueue。


二、 ArrayBlockingQueue类图结构



如图ArrayBlockingQueue内部有个数组items用来存放队列元素,putindex下标标示入队元素下标,takeIndex是出队下标,count统计队列元素个数,从定义可知道并没有使用volatile修饰,这是因为访问这些变量使用都是在锁块内,并不存在可见性问题。另外有个独占锁lock用来对出入队操作加锁,这导致同时只有一个线程可以访问入队出队,另外notEmpty,notFull条件变量用来进行出入队的同步。


另外构造函数必须传入队列大小参数,所以为有界队列,默认是Lock为非公平锁。


public ArrayBlockingQueue(int capacity) {

this(capacity, false);

}

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

}


三、offer操作


在队尾插入元素,如果队列满则返回false,否者入队返回true。


public boolean offer(E e) {

//e为null,则抛出NullPointerException异常

checkNotNull(e);

//获取独占锁

final ReentrantLock lock = this.lock;

lock.lock();

try {

//如果队列满则返回false

if (count == items.length)

return false;

else {

//否者插入元素

insert(e);

return true;

}

} finally {

//释放锁

lock.unlock();

}

}

private void insert(E x) {

//元素入队

items[putIndex] = x;

//计算下一个元素应该存放的下标

putIndex = inc(putIndex);

++count;

notEmpty.signal();

}

//循环队列,计算下标

final int inc(int i) {

return (++i == items.length) ? 0 : i;

}


这里由于在操作共享变量前加了锁,所以不存在内存不可见问题,加过锁后获取的共享变量都是从主内存获取的,而不是在CPU缓存或者寄存器里面的值,释放锁后修改的共享变量值会刷新会主内存中。


另外这个队列是使用循环数组实现,所以计算下一个元素存放下标时候有些特殊。另外insert后调用 notEmpty.signal();是为了激活调用notEmpty.await()阻塞后放入notEmpty条件队列中的线程。


四、put操作


在队列尾部添加元素,如果队列满则等待队列有空位置插入后返回。


public void put(E e) throws InterruptedException {

checkNotNull(e);

final ReentrantLock lock = this.lock;

//获取可被中断锁

lock.lockInterruptibly();







请到「今天看啥」查看全文