天增的博客
首页
博客
  • 分布式解决方案
  • Java并发工具包
  • redis
  • LeetCode
  • 系统设计
  • JVM体系
Github (opens new window)
Rss (opens new window)
  • zh-CN
  • en-US
首页
博客
  • 分布式解决方案
  • Java并发工具包
  • redis
  • LeetCode
  • 系统设计
  • JVM体系
Github (opens new window)
Rss (opens new window)
  • zh-CN
  • en-US
  • Java并发工具包
  • 并发基础
    • 线程基础
      • Thread的状态
      • 进程与线程
      • 正确停止线程的方式
      • Thread的实现方式
      • waitnotifynotifyAll
      • 生产者消费者模型
    • 线程安全
      • 线程不安全
      • 线程安全
      • 需要注意线程安全问题的情况
  • 并发工具
    • 线程协作
      • Semaphore信号量
      • CountDownLatch详解
      • 使用CompletableFuture解决旅游平台问题
      • 使用CyclicBarrier解决团建问题
    • Future
      • Future主要功能
      • FutureTask源码分析
    • ThreadLocal
      • ThreadLocal内存泄漏
      • ThreadLocal使用场景
    • 原子类
      • 原子类的作用概览
      • 原子类的性能分析
    • 阻塞队列
      • 常见的阻塞队列
      • 阻塞队列的常用方法
      • 什么是阻塞队列
        • 阻塞队列的作用
        • 主要并发队列关系图
        • 阻塞队列的特点
    • 并发容器
      • HashMap
      • CopyOnWriteArrayList
      • ConcurrentHashMap详解
    • 线程池
      • 为什么多线程会带来性能问题
      • 线程池的优势
      • 创建线程池的参数
        • 如何设置线程数
      • 线程池线程复用原理
      • ForkJoin框架
    • 各种锁
      • 锁的种类和特点
        • 公平锁非公平锁
        • 自旋锁非自旋锁
        • 共享锁独占锁
        • 乐观锁和悲观锁
      • JVM锁优化
      • synchronized和Lock的对比
      • lock的常用方法
  • 底层原理
    • CAS原理
    • AQS框架
    • 伪共享
    • java内存模型
      • Java内存模型介绍
      • happens-before规则
  • topic
  • Java并发工具包
  • 并发工具
  • 阻塞队列
  • 什么是阻塞队列
2022-04-21
目录

什么是阻塞队列

# 什么是阻塞队列

顾名思义,阻塞队列就是一组阻塞的队列,由于队列的特性是先进先出 , 如果加上阻塞这个特性的话,就会变成 队列为空时,出阻塞; 队列满时,进阻塞;

# 阻塞队列的作用

利用这种特性,我们在很多场景下都可以利用线程安全来优雅的解决我们业务自身的线程安全问题,比如可以方便的编写线程安全的生产消费模型。

生产者只需要往队列里面不停地添加元素,消费者只需要从队列里面取出他们,如下图所示:

阻塞队列

左侧有三个生产者线程,它会将生产出来的结果放到中间的阻塞队列中。

右侧有三个消费者线程,它们将会从阻塞队列中取出它所需要的内容并进行处理。

因为,阻塞队列天然是线程安全的,所以生产者和消费者都可以是多线程的,不会发生线程安全问题。

既然,阻塞队列是线程安全的,那么我们就可以将开发重心从保持线程安全性,转移到具体的业务逻辑中,大大的降低了开发的难度和工作量。

与此同时,队列的使用还能够解耦业务逻辑。

比如一个银行转账的程序,那么生产者线程不需要关心具体的转账逻辑,只需要把转账任务,如账户和金额放到队列中就可以,而不需要关心银行这个类如何去实现具体的转账业务,而作为银行这个类来讲,它会去从队列中取出来将要执行的具体的任务,再去通过自己的各种方法来完成本次转账。

# 主要并发队列关系图

image-20211203141948403

上图展示了,队列Queue主要的实现类,可以看出,Java提供线程安全的队列分别为阻塞队列和非阻塞队列两大类。

阻塞队列都是BlockingQueue的实现类:

  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • SynchronousQueue
  • DelayQueue
  • PriorityBlockingQueue
  • LinkedTransferQueue

和非阻塞队列 ConcurrentLinkedQueue.

除此之外,还有双端队列Deque: 它从头和尾都能添加和删除元素;而普通的 Queue 只能从一端进入,另一端出去。

还有扩展了BlockingQueue的TransferQueue: 生产者会一直阻塞直到所添加到队列的元素被某一个消费者所消费(不仅仅是添加到队列里就完事)

后面我们会一一介绍他们。

# 阻塞队列的特点

阻塞队列区别于其他类型的队列的最主要的特点就是"阻塞"。

阻塞功能使得生产者和消费者两段的能力得以平衡,当任何一端的速度过快时,阻塞队列便会把过快的速度给降下来,阻塞最重要的两个方法是take方法和put方法。

  • take 方法

    take 方法的功能是获取并移除队列的头结点,通常在队列里有数据的时候是可以正常移除的。可是一旦执行 take 方法的时候,队列里无数据,则阻塞,直到队列里有数据。

    一旦队列里有数据了,就会立刻解除阻塞状态,并且取到数据。

  • put方法

    put 方法插入元素时,如果队列没有满,那就和普通的插入一样是正常的插入,但是如果队列已满,那么就无法继续插入,则阻塞,直到队列里有了空闲空间。如果后续队列有了空闲空间,比如消费者消费了一个元素,那么此时队列就会解除阻塞状态,并把需要添加的数据添加到队列中。

以上过程中的阻塞和解除阻塞,都是 BlockingQueue 完成的,不需要我们自己处理。

# 是否有界(容量有多大)

此外,阻塞队列还有一个非常重要的属性,那就是容量的大小,分为有界和无界两种。

无界队列意味着里面可以容纳非常多的元素,例如 LinkedBlockingQueue 的上限是 Integer.MAX_VALUE,约为 2 的 31 次方,是非常大的一个数,可以近似认为是无限容量,因为我们几乎无法把这个容量装满。

但是有的阻塞队列是有界的,例如 ArrayBlockingQueue 如果容量满了,也不会扩容,所以一旦满了就无法再往里放数据了。

最近更新
01
以 root 身份启动 transmission-daemon
12-13
02
Debian系统安装qbittorrent-nox
12-09
03
LXC Debain12安装zerotier并实现局域网自动nat转发
07-29
更多文章>
Theme by Vdoing | Copyright © 2015-2024 天增 | 苏ICP备16037388号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式