BlockingQueue、ArrayBlockingQueue、LinkedBlockingQueue原理分析_arrayblockqueue concurrentlinkeddeque

最全的Linux教程,Linux从入门到精通

======================

  1. linux从入门到精通(第2版)

  2. Linux系统移植

  3. Linux驱动开发入门与实战

  4. LINUX 系统移植 第2版

  5. Linux开源网络全栈详解 从DPDK到OpenFlow

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

第一份《Linux从入门到精通》466页

====================

内容简介

====

本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。

需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ArrayBlockingQueue的源码解析

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {

    //队列底层容器
    final Object[] items;

    /** 下一个 take, poll, peek or remove的数组下标位置 */
    int takeIndex;

    /** 下一个 next put, offer, or add的数组下标位置 */
    int putIndex;

    /** 数组的已有数量 */
    int count;

    /**  队列锁******/
    final ReentrantLock lock;

    /** 获取队列数据的的condition等待队列 */
    private final Condition notEmpty;

    /** 存入队列数据的condition 等待队列*/
    private final Condition notFull;

    transient Itrs itrs = null;

     //队列构造方法必须指定大小,有界队列
    public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }

    // boolean fair ture为公平锁,严格的按照FIFO的原则获取锁,默认非公平锁
    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();
    }

    代码省略。。。。。。。。
}

接下来看源码分析ArrayBlockingQueue是如何对队列进行add-remove put-take offer-poll

  //add方法实际是调用的offer方法如如果成功返回true 否则抛出异常   
   public boolean add(E e) {
        return super.add(e);
    }

 
    public boolean offer(E e) {
        //检查传入的数据是否为空
        checkNotNull(e);
         // 定义锁 final变量,构造器类初始化的时候就已经申请好,state变量初始化好内存。
        final ReentrantLock lock = this.lock;
        lock.lock();
        try { 
           //判断当前的count是否等于数组的容量
           // 是返回fasle 否则加入到队列中
            if (count == items.length)
                return false;
            else {
                enqueue(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }

      private void enqueue(E x) {
        final Object[] items = this.items;
         // putIndex 入队的下一个数组下标值
        items[putIndex] = x;
//需要将putIndex重新设置为0,这是因为当前队列执行元素获取时总是从队列头部获取,而添加元素从中//从队列尾部获取所以当队列索引(从0开始)与数组长度相等时,
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        //当队列数据不为空时唤醒取数队列的等待condtion表示可以去获取数据了
        notEmpty.signal();
    }


    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        //中断锁。当前线程可以响应中断 中断后,抛出异常
        lock.lockInterruptibly();
        try {
            while (count == items.length)
               //当队列满了以后,那么入队的condition等待队列 等待,将该线程加入的等待队列中
                notFull.await();
            //否则入队操作
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

LinkedBlockingQueue的源码解析

public class LinkedBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
   
     //存储数据的节点
    static class Node<E> {
        E item;
        Node<E> next;
        Node(E x) { item = x; }
    }

    /** 容量大小 默认为 Integer.MAX_VALUE */
    private final int capacity;

    /** 当前队列的数量 */
    private final AtomicInteger count = new AtomicInteger();

     //头节点
    transient Node<E> head;

    //尾节点
    private transient Node<E> last;

    /** 取数据锁对象 */
    private final ReentrantLock takeLock = new ReentrantLock();

    /**  Wait queue for waiting takes  */
    private final Condition notEmpty = takeLock.newCondition();

    /** put数据锁对象 */
    private final ReentrantLock putLock = new ReentrantLock();

    /** 等待队列条件 */
    private final Condition notFull = putLock.newCondition();

由上面的LinkedBlockingQueue源码可以分析到 LinkedBlockingQueue 是一个基于链表的阻塞的无边界的队列。默认的队列容量为Integer.MAX_VALUE  当然这样容易引发的问题,当入列速率远超过出队速率时,可能会造成内存溢出、即超出容量的最大值。另外ArrayBlockingQueue入队与出队只有一把锁。但是LinkedBlockingQueue入队和出队是不同的锁对象、提高了队列的吞吐量

public boolean offer(E e) {
        if (e == null) throw new NullPointerException();
        final AtomicInteger count = this.count;
        if (count.get() == capacity)
            return false;
        int c = -1;
        Node<E> node = new Node<E>(e);
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            if (count.get() < capacity) {
                enqueue(node);
                c = count.getAndIncrement();
                if (c + 1 < capacity)
                    // 如果容量还够。唤醒入队的condtion去写入数据
                    notFull.signal();
            }
        } finally {
            putLock.unlock();
        }
        if (c == 0)
             // 如果容量为0表示队列还有一条数据 (原来的值为-1) 。唤醒入队的condtion去写入数据
            signalNotEmpty();
        return c >= 0;
    }

take阻塞获取的方法

public E take() throws InterruptedException {
        E x;
        int c = -1;
        //获取当前队列大小
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();//可中断
        try {
            //如果队列没有数据,挂机当前线程到条件对象的等待队列中
            while (count.get() == 0) {
                notEmpty.await();
            }
            //如果存在数据直接删除并返回该数据
            x = dequeue();
            c = count.getAndDecrement();//队列大小减1
            if (c > 1)
                notEmpty.signal();//还有数据就唤醒后续的消费线程
        } finally {
            takeLock.unlock();
        }
        //满足条件,唤醒条件对象上等待队列中的添加线程
        if (c == capacity)
            signalNotFull();
        return x;
    }

LinkedBlockingDeque是一个双向的阻塞的无边界的队列相比于LinkedBlockingDeque

可以任意的选择向链表的的头部添加数据还是向链表的尾部添加数据。当然也可以选择取数据的方向、

public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {

    void addFirst(E e);

    void addLast(E e);

    boolean offerFirst(E e);

    boolean offerLast(E e);

    。。。代码省略。。。
 }
    public E takeFirst() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E x;
           // 如果获取到的头结点中的数据为空 那么消费数据的线程挂起 等待
            while ( (x = unlinkFirst()) == null)
                notEmpty.await();
            return x;
        } finally {
            lock.unlock();
        }
    }


  private E unlinkFirst() {
      
        Node<E> f = first;


![](https://i-blog.csdnimg.cn/blog_migrate/67a7ab1cb477ab52f92c8bd2c7ebcbdf.png)


最全的Linux教程,Linux从入门到精通

======================

1.  **linux从入门到精通(第2版)**

2.  **Linux系统移植**

3.  **Linux驱动开发入门与实战**

4.  **LINUX 系统移植 第2版**

5.  **Linux开源网络全栈详解 从DPDK到OpenFlow**



![华为18级工程师呕心沥血撰写3000页Linux学习笔记教程](https://i-blog.csdnimg.cn/blog_migrate/9e13e8a2c79262a0a58eada81c722347.png)



第一份《Linux从入门到精通》466页

====================

内容简介

====

本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。



![华为18级工程师呕心沥血撰写3000页Linux学习笔记教程](https://i-blog.csdnimg.cn/blog_migrate/c34b503f3271f358bf4e505ee0f59484.jpeg)



**本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。**

> 需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.youkuaiyun.com/topics/618635766)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值