关于队列的小知识

队列是常用的数据结构之一,是一种先入先出(First Input First Output)的结构。

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。

使用场景

队列一般用于生产者-消费者模式。队列有阻塞队列和非阻塞队列,两者区别为当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。这两者都能用于生产者-消费者模式,但是在选择上有细微区别。

  1. 阻塞队列
  • 供小于求的情况使用阻塞队列更加合适。如果不使用阻塞队列,则会不断轮询,耗费资源。为防止消费进程长时间等待,可以设置超时时间来解决这个问题。

  • 阻塞队列为有界队列,能够设置队列长度

  1. 非阻塞队列
  • 非阻塞队列性能更高

  • 对于实时性不那么高的场景,生产者不断生产,消费者定时消费

  • 非阻塞队列为无界队列

项目中自己写阻塞队列的情况比较少,一般消费MQ的时候会自动阻塞,超过一定时间没有消息会自动断开链接。

非阻塞队列在商品收藏功能上用过。因为商品收藏功能QPS相对高,而且会直接操作DB,导致服务不稳定。收藏业务不需要特别实时,点击收藏按钮后按钮变红,用户查看收藏列表能查看到收藏的商品,很少有人点击收藏后立即查看收藏列表。所以使用Redis的队列存储收藏请求,起定时脚本每分钟定时进行消费。

线程安全的并发队列

队列使用起来方便,但在实际生产中,需要考虑并发情况下,线程安全问题。

对于Java来说,本身提供了线程安全的并发队列:

  • 非阻塞队列:ConcurrentLinkedQueue(无界线程安全),采用CAS机制(compareAndSwapObject原子操作)。对于CAS机制,建议看线程安全的并发队列,https://blog.csdn.net/liuxiao723846/article/details/88382520 讲解的十分详细,而且能够感受到算法的精妙。

  • 阻塞队列:ArrayBlockingQueue(有界)、LinkedBlockingQueue(无界)、DelayQueue、PriorityBlockingQueue,采用锁机制;使用 ReentrantLock 锁。对于ReentrantLock,建议看ReentrantLock 锁详解https://blog.csdn.net/zhengzhaoyang122/article/details/110847701,里面包含大量细节。

对于Go来说,有双向链表list,可以实现队列的功能,但该结构并不是线程安全的,如果想并发使用,需要使用sync保证线程安全。

总结

重新看一下基础知识挺有意思的,总能发现很多新的知识点,也能将以前用过的知识归纳总结,还能提供一些新的写作思路。写这篇博客的时候,发现锁可是太有意思了,所以下一篇博客我打算写一下Go语言里的锁,欢迎大家到时候观看。

资料

  1. 阻塞队列与非阻塞队列区别应用场景

  2. 阻塞队列的使用场景?

  3. 简单,高效,实用的非阻塞(无锁)和阻塞并行队列算法

  4. 阻塞队列与非阻塞队列的区别

  5. [怀旧并发06]分析ReentrantLock的实现原理

  6. 什么是可重入

  7. 线程安全的并发队列

  8. CAS无锁算法与ConcurrentLinkedQueue

  9. ReentrantLock 锁详解

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

图片

往期文章回顾:

  1. 设计模式

  2. 招聘

  3. 思考

  4. 存储

  5. 算法系列

  6. 读书笔记

  7. 小工具

  8. 架构

  9. 网络

  10. Go语言

猜你喜欢

转载自blog.csdn.net/shida219/article/details/118482967
今日推荐