ArrayBlockingQueue

​ArrayBlockingQueue跟LinkedBlockingQueue差不多,都是解决ConcurrentLinkedQueue的两个问题:队列的无界和读数据不一致问题。实现上LinkedBlockingQueue使用的两把重入锁:putlock和takelock,底层使用单链表。ArrayBlockingQueue使用的一把重入锁,底层使用数组。

为什么ArrayBlockingQueue使用一把锁而LinkedBlockingQueue使用两把锁

  1. ArrayBlockingQueue耗时主要在元素的插入和删除,因为ArrayBlockingQueue底层使用的数组,而锁的竞争是其次,虽然说使用两把锁可以减少锁的竞争,但此时的代码复杂度会大大增加,而效率提高并不是很明显

  2. LinkedBlockingQueue的元素的插入和删除确是非常快,因为底层使用的单链表,而锁的竞争耗时才是优化的重点。

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();}}enqueue(e);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();}

总结:

  1. 使用了ReentrantLock对方法进行加锁,当元素数量达到数组长度时使用notFull的condition进入await列表

  2. 入队实际上就是把元素放入数组putIndex位置,然后对putIndex+1后的数值进行判断,如果等于数组长度则putIndex设置为0。说明元素此时已经放过数组一轮的位置了,而且通过之前的判断,现在元素的数量是没有达到数组长度的,所以数组前面的元素肯定有被take的,所以此时应该重新开始放元素

  3. 然后count++;,记得LinkedBlockingQueue使用的AtomiInteger,而这里直接使用了int,这是因为LinkedBlockingQueue使用的两把锁,put和take互不干扰,所以count有多线程操作,而ArrayBlockingQueue使用的是一把锁,put和take互斥。这里用int完全不会有多线程操作

  4. 放了之后直接用notEmpty.signal();而LinkedBlockingQueue那边是有判断c==0,感觉还是LinkedBlockingQueue逻辑好一点,不判断的话可能就空调用了signal。同一个作者写的,为什么会写出两个逻辑,不是很理解

take()方法

 
public E take() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == 0)notEmpty.await();return dequeue();} finally {lock.unlock();}}dequeue();private E dequeue() {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;}

总结:

  1. 使用了ReentrantLock对方法进行加锁,当元素数量为0时使用notEmpty的condition进入await列表

  2. 拿到数组takeIndex位置上的元素,然后把数组takeIndex位置设置为null

  3. 然后对takeIndex+1后的数值进行判断,如果等于数组长度则takeIndex设置为0。说明元素此时已经取过数组一轮的位置了,而且通过之前的判断,现在元素的数量不为0,所以数组前面位置肯定有被put的,所以此时可以重新开始取元素。

  4. count--;和notFull.signal();跟put原理一样,这里不多说了

公众号同名,欢迎关注 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值