当前位置:网站首页>阻塞队列之LinkedBlockingQueue分析
阻塞队列之LinkedBlockingQueue分析
2020-11-06 01:18:00 【ClawHub的博客】
1、五种阻塞队列介绍
- ArrayBlockingQueue
有界队列,底层使用数组实现,并发控制使用ReentrantLock控制,不管是插入操作还是读取操作,都需要获取锁之后才能执行。 - LinkedBlockingQueue
底层基于单向链表实现,既可以当做有界队列,也可以当做无界队列使用。使用两个ReentrantLock实现并发控制:takelock和putlock。 - SynchronousQueue
底层使用单向链表实现,只有一个元素,同步的意思是一个写操作必须等到一个读操作之后才返回,指的是读写线程的同步。 - PriorityBlockingQueue
带排序的阻塞队列的实现,使用数组进行实现。并发控制使用ReentrantLock,队列为无界队列。
有初始化参数指定队列大小,但是会自动扩容。使用最小堆来实现排序。 - DelayedQueue
DelayedQueue是使用PriorityBlockingQueue和Delayed实现的,内部定义了一个优先级队列,当调用offer的时候,把Delayed对象加入队列中,使用take先把first对象拿出来(peek),如果没有到达阈值,进行await处理。
2、poll和peek的区别
都用于取队列的头结点,poll会删除头结点,peek不会删除头结点。
3、LinkedBlockingQueue
- 是先进先出队列FIFO。
- 采用ReentrantLock保证线程安全
3.1、功能
3.1.1、增加
增加有三种方式,前提:队列满
方式 | put | add | offer |
---|---|---|---|
特点 | 一直阻塞 | 抛异常 | 返回false |
3.1.2、删除
删除有三种方式,前提:队列为空
方式 | remove | poll | take |
---|---|---|---|
特点 | NoSuchElementException | 返回false | 阻塞 |
3.2、简单分析
- LinkedBlockingQueue是一个阻塞队列,内部由两个ReentrantLock来实现出入队列的线程安全,由各自的Condition对象的await和signal来实现等待和唤醒功能。
- 基于单向链表的、范围任意的(其实是有界的)、FIFO 阻塞队列。
- 头结点和尾结点一开始总是指向一个哨兵的结点,它不持有实际数据,当队列中有数据时,头结点仍然指向这个哨兵,尾结点指向有效数据的最后一个结点。这样做的好处在于,与计数器 count 结合后,对队头、队尾的访问可以独立进行,而不需要判断头结点与尾结点的关系。
3.2.1、节点与属性
1 |
//链表节点内部类 |
3.2.2、插入线程与获取线程的相互通知
signalNotEmpty()方法,在插入线程发现队列为空时调用,告知获取线程需要等待。
signalNotFull()方法,在获取线程发现队列已满时调用,告知插入线程需要等待。
1 |
//表示等待take。put/offer调用,否则通常不会锁定takeLock。 |
3.2.3、入队与出队操作
enqueue()方法只能在持有 putLock 锁下执行,dequeue()在持有 takeLock 锁下执行。
1 |
//在队列尾部插入 |
3.2.4、对两把锁的加锁与释放
在需要对两把锁同时加锁时,把加锁的顺序与释放的顺序封装成方法,确保所有地方都是一致的。而且获取锁时都是不响应中断的,一直获取直到加锁成功,这就避免了第一把锁加锁成功,而第二把锁加锁失败导致锁不释放的风险。
1 |
//锁定putLock和takeLock |
3.3、源码解读
简单介绍一下LinkedBlockingQueue中API的源码,如构造方法,新增,获取,删除,drainTo。
3.3.1、构造函数
LinkedBlockingQueue有三个构造方法,其中无参构造尽量少用,因为容量为Integer的最大值,操作不当会出现内存溢出。
1 |
public LinkedBlockingQueue() { |
3.3.2、offer(E e)
将给定的元素设置到队列中,如果设置成功返回true, 否则返回false。 e的值不能为空,否则抛出空指针异常。
1 |
//如果可以在不超过队列容量的情况下立即插入指定的元素到队列的尾部,成功后返回true,如果队列已满,返回false。当使用容量受限的队列时,此方法通常比方法BlockingQueue#add更可取,后者只能通过抛出异常才能插入元素。 |
3.3.3、put(E e)
将元素设置到队列中,如果队列中没有多余的空间,该方法会一直阻塞,直到队列中有多余的空间。
1 |
public void put(E e) throws InterruptedException { |
3.3.4、peek()
非阻塞的获取队列中的第一个元素,不出队列。
1 |
public E peek() { |
3.3.5、poll()
非阻塞的获取队列中的值,未获取到返回null。
1 |
public E poll() { |
3.3.6、remove(Object o)
从队列中移除指定的值。将两把锁都锁定。
1 |
public boolean remove(Object o) { |
3.3.7、clear()
清空队列。
1 |
//原子性地从队列中删除所有元素。此调用返回后,队列将为空。 |
3.3.8、drainTo(Collection c)
将队列中值,全部移除,并发设置到给定的集合中。
1 |
public int drainTo(Collection<? super E> c, int maxElements) { |
版权声明
本文为[ClawHub的博客]所创,转载请带上原文链接,感谢
https://clawhub.club/posts/2019/12/18/%E9%AB%98%E5%B9%B6%E5%8F%91/%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E4%B9%8BLinkedBlockingQueue%E5%88%86%E6%9E%90/
边栏推荐
猜你喜欢
随机推荐
給萌新HTML5 入門指南(二)
ThreadLocal原理大解析
微信小程序:防止多次点击跳转(函数节流)
nlp模型-bert从入门到精通(一)
快快使用ModelArts,零基础小白也能玩转AI!
使用NLP和ML来提取和构造Web数据
Sort the array in ascending order according to the frequency
普通算法面试已经Out啦!机器学习算法面试出炉 - kdnuggets
6.9.2 session flashmapmanager redirection management
前端模組化簡單總結
01 . Go语言的SSH远程终端及WebSocket
2018个人年度工作总结与2019工作计划(互联网)
业务策略、业务规则、业务流程和业务主数据之间关系 - modernanalyst
安装Anaconda3 后,怎样使用 Python 2.7?
通过深层神经网络生成音乐
条码生成软件如何隐藏部分条码文字
分布式ID生成服务,真的有必要搞一个
Analysis of ThreadLocal principle
DRF JWT authentication module and self customization
Menu permission control configuration of hub plug-in for azure Devops extension