26.阻塞队列BlockingQueue实战及其原理分析

阻塞队列

阻塞队列 (BlockingQueue)是Java util.concurrent包下重要的数据结构,BlockingQueue提供了线程安全的队列访问方式:当阻塞队列插入数据时,如果队列已满,线程将会阻塞等待直到队列非满;从阻塞队列取数据时,如果队列已空,线程将会阻塞等待直到队列非空。并发包下很多高级同步类的实现都是基于BlockingQueue实现的。

BlockingQueue接口

方法抛出异常返回特定值阻塞阻塞特定时间
入队add(e) = offer(e) + 异常offer(e)put(e)offer(e, time, unit)
出队remove()poll()take()poll(time, unit)
获取队首元素element()peek()不支持不支持

应用场景

使用队列实现削峰,平滑过渡到下一秒

  • 线程池
  • 生产者-消费者模型
  • 消息队列
  • 缓存系统
  • 并发任务处理

JUC包下的阻塞队列

基于数组,基于链表的实现

设计注意点: 用while不用if是为了防止虚假唤醒

  • ArrayBlockingQueue
    • 有界阻塞队列,存取相互排斥
    • 数据结构:静态数组
      • 容量固定,没有扩容机制
      • 没有元素的位置被null占位
    • 存取都使用 ReentrantLock
    • 阻塞对象
      • notEmpty:出队 count == 0时,进行阻塞
      • notFull:入队 count == items.length 时,进行阻塞
    • 双指针保证队列的先进先出
      • putIndex,到队尾时设置0,唤醒notEmpty
      • takeIndex,到队尾时设置0,唤醒notFull
  • LinkedBlockingQueue
    • 无界阻塞队列,可以指定容量,默认为Integer。MAX_VALUE,存取互不干扰。
    • 数据结构:链表,内部类 Node 存储元素。
    • 锁分离,存取操作不同的Node
      • takeLock
      • putLock
      • 删除时获取两把锁
    • 阻塞对象
      • notEmpty:出队 count == 0时,进行阻塞
      • notFull:入队 count == capacity 时,进行阻塞
    • 入队
      • last = last.next = node
    • 出队
      • first = h.next;head=first;
  • DelayQueue
    • 一个使用优先级队列实现的无界阻塞队列
    • 数据结构:PriorityQueue, 与 PriorityBlockQueue类似,不过没有阻塞功能
    • 锁:ReentrantLock
    • 阻塞对象:Condition available
    • 入队:不阻塞
    • 出队
      • 为空时阻塞
      • 检查堆顶元素过期时间
        • 小于等于0则出队
        • 大于0则阻塞
          • leader线程不为空,阻塞
          • 为空,设置当前线程为leader,并按照过期时间进行阻塞
ArrayBlockingQueueLinkedBlockingQueue
队列大小初始化必须指定大小可以有界,也可以指定
存储容器数组以Node作为连接对象的链表
新增/删除元素不会生产和销毁额外的对象实例会新增Node对象
锁实现读写使用同一ReentrantLock使用 takeLock 和 putLock 实现读写分离
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值