ArrayBlockingQueue的内部实现

走远了吗. 提交于 2020-03-25 01:46:13

3 月,跳不动了?>>>

区别

  1. ArrayBlockingQueue 、ArrayList 的内部存储结构为数组;LinkedBlockingQueue 是单向链表, LinkedBlockingDeque 、 LinkedList 是双向链表 (后三者都维护链表的head与tail引用node)
  2. ArrayBlockingQueue初始化时是一定要指定容量大小;ArrayList的默认大小为0;而LinkedBlockingQueue、LinkedBlockingDeque提供默认容量Integer.MAX_VALUE。
  3. ArrayBlockingQueue & LinkedBlockingDeque 通过同一把锁的不同Condition来控制;在操作时,生产与消费需要竞争同一把锁。
    LinkedBlockingQueue通过锁分离方式来控制(生产与消费竞争的资源是属于独立的锁。队列空时:有生产后需要唤醒等待的消费者;队列满时:有消费后需要唤醒等待的生产者;当然对于同属生产(消费)者的不同线程相互间也需要竞争生产(消费)锁)。

实现方案   

两者都是先加锁ReentrantLock, 依赖于这个锁的 [出队]等待队列  (Condition -> notEmpty)与 【入队】等待队列(Condition -> notFull) 来控制。

锁默认用的是非公平模式:NonfairSync

可以这么理解:

  • notEmpty: 标识:当前队列不是空的可以消费; 所以出队时,判定队列为空,则await这个信号;队列不为空则进行出队操作,成功后唤醒 notFull ;
  • notFull : 标识:当前队列不是满的可以生产;  所以入队时,判定队列已满,则await这个信号。队列没满则进行入队操作,成功后唤醒notEmpty;

出队

拿ArrayBlockingQueue 的出队来分析:

  1. 先加锁
  2. 判定当前的数量是否为空:
    1. 如果为空,则notEmpty(“队列不是空的”信号) 等待
    2. 如果不为空,则出队。 出队成功后, 唤醒 notFull ( "队列不是满的" 信号)
  3. 最终释放锁

入队

拿LinkedBlockingDeque 的入队来分析

  1. 先加锁
  2. 尝试出队操作:
    1. 在unlinkFirst方法中, 从首节点进行出队,出队完毕后,设置好新的First-Node,  唤醒 notFull ( "队列不是满的" 信号)
    2. 如果出队返回是null,则 notEmpty(“队列不是空的”信号) 等待

模拟ArrayBlockingQueue的生产和消费方式

package com.noob.learn.netty;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Storage {

    private int             capacity = 10;
    private Queue<Object>   queue    = new LinkedList<Object>();
    final ReentrantLock     lock     = new ReentrantLock();

    /** 当前队列不是空的,可以消费 */
    private final Condition notEmpty = lock.newCondition();

    /** 当前队列不是满的, 可以生产 */
    private final Condition notFull  = lock.newCondition();

    public void produce() {
        final ReentrantLock lock = this.lock;
        try {
            lock.lockInterruptibly();

            while (queue.size() > capacity - 1) {
                System.out.println("库存量:" + queue.size() + "已满, 暂时不能执行生产任务!");
                notFull.await();
            }

            queue.add(new Object());
            System.out.println("生产了, 现仓储量为:" + queue.size());
            notEmpty.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();

        }
    }

    public void consume() {
        final ReentrantLock lock = this.lock;
        try {
            lock.lockInterruptibly();
            while (queue.size() == 0) {
                System.out.println("库存量" + queue.size() + "暂时不能执行消费任务!");
                notEmpty.wait();
            }
            queue.remove();
            System.out.println("消费了, 现仓储量为:" + queue.size());
            notFull.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();

        }
    }

    public static void main(String[] args) throws InterruptedException {
        Storage storage = new Storage();
        new Thread(() -> {
            while (true) {
                storage.produce();
                try {
                    Thread.sleep(1000); // 执行太快了降速
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }   ).start();

        new Thread(() -> {
            while (true) {
                storage.consume();
                try {
                    Thread.sleep(1000);// 执行太快了降速
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }   ).start();
    }
}

执行结果:

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!