• 【无标题】


    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原理一样,这里不多说了

    公众号同名,欢迎关注 

  • 相关阅读:
    为了吃透25个技术栈,这份文档帮我省了大量时间,值得一看
    NumPy中einsum使用笔记
    数据分析方法与思维:漏斗分析
    openjudge 1.7.24 单词的长度
    CV每日论文---2024.6.3
    腾讯云服务器4核8G配置有哪些?多少钱一年?
    LoadRunner关联和检查点
    【Recommend System】----CTR 建模
    Linux创建与删除用户
    一文搞定注意力机制(Attention)
  • 原文地址:https://blog.csdn.net/shidebin/article/details/126817942