• 【无标题】


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

    公众号同名,欢迎关注 

  • 相关阅读:
    手把手教你Nginx常用模块详解之ngx_http_limit_conn_module(五)
    java 字节流向文件中写入指定内容
    Redis集群(Cluster)
    MongoDB安装及常用语句总结
    51驱动TTP229矩阵触摸按键模块,16键输入有效模式
    基于MatLab实现LSB(最低有效位)算法完成图片数字水印隐写功能
    02 Shell编程之条件语句
    【表情包分享】国庆假期结束了,该上班了,来分享一下你的表情包吧!
    【前端 Echarts】小白初步学习小结Echarts基本使用
    华为机试 HJ36 字符串加密【Java实现】
  • 原文地址:https://blog.csdn.net/shidebin/article/details/126817942