博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ArrayBlockingQueue源码解析(2)
阅读量:6155 次
发布时间:2019-06-21

本文共 5228 字,大约阅读时间需要 17 分钟。

此文已由作者赵计刚授权网易云社区发布。

欢迎访问,了解更多网易技术产品运营经验。

3.3、public void put(E e) throws InterruptedException

原理:

  • 在队尾插入一个元素,如果队列满了,一直阻塞,直到数组不满了或者线程被中断

使用方法:

        try {            abq.put("hello1");        } catch (InterruptedException e) {            e.printStackTrace();        }

源代码:

    /**     * 在队尾插入一个元素     * 如果队列满了,一直阻塞,直到数组不满了或者线程被中断     */    public void put(E e) throws InterruptedException {        if (e == null)            throw new NullPointerException();        final E[] items = this.items;        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            try {                while (count == items.length)//队列满了,一直阻塞在这里                    /*                     * 一直等待条件notFull,即被其他线程唤醒                     * (唤醒其实就是,有线程将一个元素出队了,然后调用notFull.signal()唤醒其他等待这个条件的线程,同时队列也不慢了)                     */                    notFull.await();            } catch (InterruptedException ie) {//如果被中断                notFull.signal(); // 唤醒其他等待该条件(notFull,即入队)的线程                throw ie;            }            insert(e);        } finally {            lock.unlock();        }    }

 

4、出队

4.1、public E poll()

原理:

  • 如果没有元素,直接返回null;如果有元素,将队头元素置null,但是要注意队头是随时变化的,并非一直是items[0]。

使用方法:

abq.poll();

源代码:

    /**     * 出队     */    public E poll() {        final ReentrantLock lock = this.lock;        lock.lock();        try {            if (count == 0)//如果没有元素,直接返回null,而非抛出异常                return null;            E x = extract();            return x;        } finally {            lock.unlock();        }    }

    /**     * 出队     */    private E extract() {        final E[] items = this.items;        E x = items[takeIndex];//获取出队元素        items[takeIndex] = null;//将出队元素位置置空        /*         * 第一次出队的元素takeIndex==0,第二次出队的元素takeIndex==1         * (注意:这里出队之后,并没有将后面的数组元素向前移)         */        takeIndex = inc(takeIndex);        --count;//数组元素个数-1        notFull.signal();//数组已经不满了,唤醒其他等待notFull条件的线程        return x;//返回出队的元素    }

 

4.2、public E poll(long timeout, TimeUnit unit) throws InterruptedException

原理:

  • 从对头删除一个元素,如果数组不空,出队;如果数组已空且已经超时,返回null;如果数组已空且时间未超时,则进入等待,直到出现以下三种情况:

    • 被唤醒

    • 等待时间超时

    • 当前线程被中断

使用方法:

        try {            abq.poll(1000, TimeUnit.MILLISECONDS);        } catch (InterruptedException e) {            e.printStackTrace();        }

源代码:

    /**     * 从对头删除一个元素,     * 如果数组不空,出队;     * 如果数组已空,判断时间是否超时,如果已经超时,返回null     * 如果数组已空且时间未超时,则进入等待,直到出现以下三种情况:     * 1、被唤醒     * 2、等待时间超时     * 3、当前线程被中断     */    public E poll(long timeout, TimeUnit unit) throws InterruptedException {        long nanos = unit.toNanos(timeout);//将时间转换为纳秒        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            for (;;) {                if (count != 0) {//数组不空                    E x = extract();//出队                    return x;                }                if (nanos <= 0)//时间超时                    return null;                try {                    /*                     * 进行等待:                     * 在这个过程中可能发生三件事:                     * 1、被唤醒-->继续当前这个for(;;)循环                     * 2、超时-->继续当前这个for(;;)循环                     * 3、被中断-->之后直接执行catch部分的代码                     */                    nanos = notEmpty.awaitNanos(nanos);                } catch (InterruptedException ie) {                    notEmpty.signal(); // propagate to non-interrupted thread                    throw ie;                }            }        } finally {            lock.unlock();        }    }

 

4.3、public E take() throws InterruptedException

原理:

  • 将队头元素出队,如果队列空了,一直阻塞,直到数组不为空或者线程被中断

使用方法:

        try {            abq.take();        } catch (InterruptedException e) {            e.printStackTrace();        }

源代码:

    /**     * 将队头元素出队     * 如果队列空了,一直阻塞,直到数组不为空或者线程被中断     */    public E take() throws InterruptedException {        final ReentrantLock lock = this.lock;        lock.lockInterruptibly();        try {            try {                while (count == 0)//如果数组为空,一直阻塞在这里                    /*                     * 一直等待条件notEmpty,即被其他线程唤醒                     * (唤醒其实就是,有线程将一个元素入队了,然后调用notEmpty.signal()唤醒其他等待这个条件的线程,同时队列也不空了)                     */                    notEmpty.await();            } catch (InterruptedException ie) {                notEmpty.signal(); // propagate to non-interrupted thread                throw ie;            }            E x = extract();            return x;        } finally {            lock.unlock();        }    }

  

总结:

1、具体入队与出队的原理图:这里只说一种情况,见下图,途中深色部分表示已有元素,浅色部分没有元素。

 

上面这种情况是怎么形成的呢?当队列满了,这时候,队头元素为items[0]出队了,就形成上边的这种情况。

假设现在又要出队了,则现在的队头元素是items[1],出队后就形成下面的情形。

 

出队后,对头元素就是items[2]了,假设现在有一个元素将要入队,根据inc方法,我们可以得知,他要插入到items[0]去,入队了形成下图:

以上就是整个入队出队的流程,inc方法上边已经给出,这里再贴一遍:

    /**     * i+1,数组下标+1     * 注意:这里这样写的原因。     */    final int inc(int i) {        return (++i == items.length) ? 0 : i;    }

 

2、三种入队对比:

  • offer(E e):如果队列没满,立即返回true; 如果队列满了,立即返回false-->不阻塞

  • put(E e):如果队列满了,一直阻塞,直到数组不满了或者线程被中断-->阻塞

  • offer(E e, long timeout, TimeUnit unit):在队尾插入一个元素,,如果数组已满,则进入等待,直到出现以下三种情况:-->阻塞

    • 被唤醒

    • 等待时间超时

    • 当前线程被中断

 

3、三种出对对比:

  • poll():如果没有元素,直接返回null;如果有元素,出队

  • take():如果队列空了,一直阻塞,直到数组不为空或者线程被中断-->阻塞

  • poll(long timeout, TimeUnit unit):如果数组不空,出队;如果数组已空且已经超时,返回null;如果数组已空且时间未超时,则进入等待,直到出现以下三种情况:

    • 被唤醒

    • 等待时间超时

    • 当前线程被中断

更多网易技术、产品、运营经验分享请。

相关文章:

【推荐】 

转载地址:http://gnbfa.baihongyu.com/

你可能感兴趣的文章
SuSE Linux上搭建apache+php+mysql环境
查看>>
Android Studio 出现Activity supporting ACTION_VIEW is not set as BROWSABLE错误
查看>>
iOS 加载动态库报错问题
查看>>
今日工作情况5
查看>>
记录git的初始设置,添加文件,提交文件
查看>>
18 行为型模式-----模板方法模式
查看>>
基于PHP的微信支付教程
查看>>
《Linux内核设计与实现》学习总结 Chap18
查看>>
const与define的对比
查看>>
sql中binary_checksum(*)的用法
查看>>
pta l2-13(红色警报)
查看>>
网页编排规则
查看>>
有图形界面的聊天程序
查看>>
ACM题解系列之一:刘汝佳:《算法竞赛入门经典》(第2版)
查看>>
codeforces 698B fix a tree 时间戳
查看>>
从新浪的分享文本字符串中,分离出@到的好友的方法
查看>>
11-02笔记图
查看>>
visual c++ 2010安装失败导致CRM2015安装失败
查看>>
web项目直接在浏览器上访问不需要带.jsp,直接ip地址加项目名 在web.xml里配置...
查看>>
一步一步使用Ext JS MVC与Asp.Net MVC 3开发简单的CMS后台管理系统之用户管理(3)...
查看>>