【JUC】阻塞队列|DelayQueue延时原理|CompletableFuture异步API大全
大家好,我是程序员二叉。
简介
本篇讲解BlockingQueue阻塞队列核心作用、四大常用队列差异与场景、DelayQueue底层延时实现、CompletableFuture全套高频异步API,生产环境高频工具类面试必背。欢迎点赞关注收藏。
一、BlockingQueue 阻塞队列核心作用
- 线程安全容器:自带锁机制,多线程并发put/take无竞态异常
- 双向阻塞能力
- 队列已满:生产者调用put()阻塞等待空位
- 队列为空:消费者调用take()阻塞等待元素
- 解耦生产者-消费者模型,削峰填谷,平衡上下游线程执行速度
- 自带批量操作、超时存取、非阻塞存取多种API适配不同业务
二、四大主流阻塞队列区别&适用场景
1. ArrayBlockingQueue
- 底层:有界固定数组,初始化必须指定容量
- 锁机制:全局一把ReentrantLock,读写操作互斥不能并行
- 适用:流量可控、固定缓冲大小的同步生产消费场景
2. LinkedBlockingQueue
- 底层:单向链表,默认无界,可传容量设为有界
- 锁机制:生产者、消费者两把独立锁,读写可并行,吞吐量更高
- 适用:高吞吐异步任务、ThreadPoolExecutor线程池默认工作队列
3. SynchronousQueue
- 无存储缓冲区,不存放任何元素;put必须匹配一个take才交付
- 支持公平/非公平模式,无容量限制
- 适用:瞬时高并发、任务不排队,CachedThreadPool底层队列
4. DelayQueue
- 无界优先阻塞队列,元素必须实现Delayed延时接口
- 只有延时到期的元素才能被take取出
- 适用:定时任务、订单超时关闭、会话过期、接口延迟重试
三、DelayQueue 底层完整原理
- 内部依托PriorityQueue优先队列,按照元素剩余延时时间升序排序,队首是最快到期任务
- 全局一把ReentrantLock,搭配一个Condition等待队列
- take()执行流程:
- 加锁取出队首延时任务
- 判断延时是否到期,到期直接取出返回
- 未到期则await阻塞等待,释放锁
- 新延时任务入队会唤醒阻塞线程,重新校验队首时间
- 业务元素实现Delayed接口,重写
getDelay()返回剩余延时毫秒
四、CompletableFuture 高频常用API
1. 创建异步任务
// 无返回值异步CompletableFuture.runAsync(Runnabletask);// 有返回值异步CompletableFuture.supplyAsync(Supplier<T>task);2. 完成回调(成功 / 失败都会执行)
whenComplete(BiConsumer<T, Throwable>)
3. 异常单独兜底处理
exceptionally(Function<Throwable,T>)异常时返回默认兜底结果
4. 串行链式执行
thenApply():接收上一步结果,转换返回新值thenAccept():消费上一步结果,无返回值thenRun():不接收结果,单纯执行后续任务
5. 多任务组合编排
thenCombine():两个任务全部完成,合并两者结果applyToEither():两个任务谁先执行完,使用最先完成的结果allOf():阻塞等待所有异步任务全部执行完毕anyOf():任意一个任务完成就立刻结束等待
6. 阻塞获取结果
get():阻塞拿结果,抛出受检异常get(long, TimeUnit):带超时阻塞获取join():阻塞拿结果,只抛运行时异常,无需 try-catch 受检异常
面试速记总结
- 阻塞队列平衡生产消费;
Array固定数组、Linked双锁高吞吐、Synchronous零缓冲 DelayQueue基于优先队列排序延时任务,到期才可取出CompletableFuture替代原始Future,支持链式回调、多任务组合、异常统一处理
