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

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


1、对于LinkedBlockingQueue需要掌握以下几点

  • 创建

  • 入队(添加元素)

  • 出队(删除元素)

2、创建

Node节点内部类与LinkedBlockingQueue的一些属性

    static class Node<E> {E item;//节点封装的数据/*** One of:* - the real successor Node* - this Node, meaning the successor is head.next* - null, meaning there is no successor (this is the last node)*/Node<E> next;//下一个节点Node(E x) { item = x; }}/** 指定链表容量  */private final int capacity;/** 当前的元素个数 */private final AtomicInteger count = new AtomicInteger(0);/** 链表头节点 */private transient Node<E> head;/** 链表尾节点 */private transient Node<E> last;/** 出队锁 */private final ReentrantLock takeLock = new ReentrantLock();/** 出队等待条件 */private final Condition notEmpty = takeLock.newCondition();/** 入队锁 */private final ReentrantLock putLock = new ReentrantLock();/** 入队等待条件 */private final Condition notFull = putLock.newCondition();

2.1、public LinkedBlockingQueue(int capacity)

使用方法:

Queue<String> abq = new LinkedBlockingQueue<String>(1000);

源代码:

    /*** 创建一个 LinkedBlockingQueue,容量为指定容量*/public LinkedBlockingQueue(int capacity) {if (capacity <= 0) throw new IllegalArgumentException();this.capacity = capacity;last = head = new Node<E>(null);//初始化头节点和尾节点,均为封装了null数据的节点}

注意点:

  • LinkedBlockingQueue的组成一个链表+两把锁+两个条件

2.2、public LinkedBlockingQueue()

使用方法:

Queue<String> abq = new LinkedBlockingQueue<String>();

源代码:

    /*** 创建一个LinkedBlockingQueue,容量为整数最大值*/public LinkedBlockingQueue() {this(Integer.MAX_VALUE);}

注意点:默认容量为整数最大值,可以看做没有容量限制

3、入队:

3.1、public boolean offer(E e)

原理:

  • 在队尾插入一个元素, 如果队列没满,立即返回true; 如果队列满了,立即返回false

使用方法:

  • abq.offer("hello1");

源代码:

    /*** 在队尾插入一个元素, 容量没满,可以立即插入,返回true; 队列满了,直接返回false* 注:如果使用了限制了容量的队列,这个方法比add()好,因为add()插入失败就会抛出异常*/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;final ReentrantLock putLock = this.putLock;putLock.lock();// 获取入队锁try {if (count.get() < capacity) {// 容量没满enqueue(e);// 入队c = count.getAndIncrement();// 容量+1,返回旧值(注意)if (c + 1 < capacity)// 如果添加元素后的容量,还小于指定容量(说明在插入当前元素后,至少还可以再插一个元素)notFull.signal();// 唤醒等待notFull条件的其中一个线程}} finally {putLock.unlock();// 释放入队锁}if (c == 0)// 如果c==0,这是什么情况?一开始如果是个空队列,就会是这样的值,要注意的是,上边的c返回的是旧值signalNotEmpty();return c >= 0;}
    /*** 创建一个节点,并加入链表尾部* @param x*/private void enqueue(E x) {/** 封装新节点,并赋给当前的最后一个节点的下一个节点,然后在将这个节点设为最后一个节点*/last = last.next = new Node<E>(x);}
    private void signalNotEmpty() {final ReentrantLock takeLock = this.takeLock;takeLock.lock();//获取出队锁try {notEmpty.signal();//唤醒等待notEmpty条件的线程中的一个} finally {takeLock.unlock();//释放出队锁}}

如果,入队逻辑不懂,查看最后总结部分入队逻辑的图,代码非常简单,流程看注释即可。

3.2、public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException

原理:

  • 在队尾插入一个元素,,如果队列已满,则进入等待,直到出现以下三种情况:

    • 被唤醒

    • 等待时间超时

    • 当前线程被中断

使用方法:

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

源代码:

    /*** 在队尾插入一个元素,,如果队列已满,则进入等待,直到出现以下三种情况: * 1、被唤醒 * 2、等待时间超时 * 3、当前线程被中断*/public boolean offer(E e, long timeout, TimeUnit unit)throws InterruptedException {if (e == null)throw new NullPointerException();long nanos = unit.toNanos(timeout);// 转换为纳秒int c = -1;final ReentrantLock putLock = this.putLock;// 入队锁final AtomicInteger count = this.count;// 总数量putLock.lockInterruptibly();try {while (count.get() == capacity) {// 容量已满if (nanos <= 0)// 已经超时return false;/** 进行等待: 在这个过程中可能发生三件事: * 1、被唤醒-->继续当前这个while循环* 2、超时-->继续当前这个while循环 * 3、被中断-->抛出中断异常InterruptedException*/nanos = notFull.awaitNanos(nanos);}enqueue(e);// 入队c = count.getAndIncrement();// 入队元素数量+1if (c + 1 < capacity)notFull.signal();} finally {putLock.unlock();}if (c == 0)signalNotEmpty();return true;}

注意:

  • awaitNanos(nanos)是AQS中的一个方法,这里就不详细说了,有兴趣的自己去查看AQS的源代码。

免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

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

相关文章:
【推荐】 LESS+to+MCSS
【推荐】 BRVAH(让RecyclerView变得更高效) (2)
【推荐】 微服务化之缓存的设计

LinkedBlockingQueue源码解析(1)相关推荐

  1. 面试官系统精讲Java源码及大厂真题 - 19 LinkedBlockingQueue 源码解析

    19 LinkedBlockingQueue 源码解析 更新时间:2019-10-11 17:02:21 从不浪费时间的人,没有工夫抱怨时间不够. --杰弗逊 引导语 说到队列,大家的反应可能是我从来 ...

  2. Android多线程之ArrayBlockingQueue源码解析

    阻塞队列系列 Android多线程之LinkedBlockingQueue源码解析 Android多线程之SynchronousQueue源码解析 Andorid多线程之DelayQueue源码分析 ...

  3. Android之DiskLruCache源码解析

    转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/73863258 本文出自:[顾林海的博客] 个人开发的微信小程序,目前功 ...

  4. dubbo源码解析(三十五)集群——cluster

    集群--cluster 目标:介绍dubbo中集群容错的几种模式,介绍dubbo-cluster下support包的源码. 前言 集群容错还是很好理解的,就是当你调用失败的时候所作出的措施.先来看看有 ...

  5. dubbo源码解析(九)远程通信——Transport层

    远程通讯--Transport层 目标:介绍Transport层的相关设计和逻辑.介绍dubbo-remoting-api中的transport包内的源码解析. 前言 先预警一下,该文篇幅会很长,做好 ...

  6. 阻塞队列和ArrayBlockingQueue源码解析

    什么是阻塞队列 当队列中为空时,从队列总获取元素的操作将被阻塞,当队列满时,向队列中添加元素的操作将被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,知道其它的线程往队列中插入新的元素.同样,试图 ...

  7. Heritrix 3.1.0 源码解析(六)

    本文分析BdbFrontier对象的相关状态和方法 BdbFrontier类继承自WorkQueueFrontier类   WorkQueueFrontier类继承自AbstractFrontier类 ...

  8. 面试官系统精讲Java源码及大厂真题 - 37 ThreadPoolExecutor 源码解析

    37 ThreadPoolExecutor 源码解析 当你做成功一件事,千万不要等待着享受荣誉,应该再做那些需要的事. -- 巴斯德 引导语 线程池我们在工作中经常会用到.在请求量大时,使用线程池,可 ...

  9. 面试官系统精讲Java源码及大厂真题 - 28 Future、ExecutorService 源码解析

    28 Future.ExecutorService 源码解析 今天应做的事没有做,明天再早也是耽误了. 引导语 本章和大家一起看下有返回值的线程如何创建,两种线程 API 之间如何关联,介绍一下和线程 ...

最新文章

  1. Spring Boot 2.6之后,动态权限控制终于可以用起来了!
  2. php数据访问(查询)
  3. Codeforces Round #722 (Div. 2)
  4. Ubuntu 14.10 -- 异次元软件世界
  5. 多台tomcat服务的session共享 memcached与redis
  6. Kubernetes Pod入门指南
  7. 关于gcc的一点小人性化提示
  8. Parallels Desktop虚拟机如何安装win10和win11,懒人安装教程
  9. Numpy:numpy包下载并导入Pycharm的方法
  10. drawboard pdf拆分文件_Drawboard PDF 免费版
  11. Win11系统开启控制面板会闪退怎么解决?
  12. 京东商城逆势融资B2C成投资热土
  13. 三星为什么能超越SONY在世界崛起?
  14. mysql候选关键字_MySQL Key值(PRI, UNI, MUL)的含义、超键(super key)、候选键(candidate key)、主键(primary key)...
  15. Apache网页优化
  16. 第85节:Java中的JavaScript
  17. 0基础不用怕,从0到1轻松教你入门Python
  18. 微信小程序系列一:获取头像昵称
  19. 关于ELF格式文件里面的调试信息解读
  20. python中文转16进制_Python 16进制与中文相互转换的实现方法

热门文章

  1. android 封装状态页面,Android 缺省页状态切换方案
  2. 启动mysql服务是报错找不到pid_mysql报错 The server quit without updating PID file
  3. mysql利用存储过程批量插入数据
  4. ckplayer php,ckplayer 网页视频播放插件
  5. php文件下载到服务器代码,PHP文件下载实例代码浅析
  6. php读取binlog,PHP解析Mysql Binlog
  7. 智能车竞赛技术报告 | 智能车视觉 - 西南科技大学 - 西科二队
  8. 2021年春季学期-信号与系统-第八次作业参考答案-第四小题
  9. 2021年春季学期-信号与系统-第七次作业参考答案-第七小题
  10. 2021年春季学期-信号与系统-第四次作业参考答案-第十二小题