文章目录

📙 作者: 编程技术圈(哇哥面试陪跑)
👉 欢迎关注、分享、评论
✔️ 持续分享更多干货内容
🌐🌏🌎➕tcmeta, 欢迎沟通交流
零、引入
“秒杀系统响应慢成龟速!QPS 才 500,用户全卡在下单页面!” 王二又愁眉苦脸地找哇哥,上次用 ArrayBlockingQueue 解决了订单丢单问题,但秒杀高峰期,订单处理还是慢得离谱,领导拍桌子要求 QPS 提到 1000,不然卷铺盖走人。
哇哥扫了眼王二的代码,乐了:“你用 ArrayBlockingQueue 存秒杀订单,相当于先把订单堆在队列里,再慢慢处理 —— 秒杀要的是‘即时处理’,得用 SynchronousQueue!这玩意儿没队列存储,订单直接从用户手里交到处理线程手里,响应快一倍!”
点赞 + 关注,跟着哇哥和王二,玩转阻塞队列的高级玩法,秒杀系统 QPS 翻倍,面试还能多拿 5k!
一、王二的秒杀坑:ArrayBlockingQueue 的 “存储瓶颈”
王二的秒杀系统用 ArrayBlockingQueue 做订单队列:生产者(用户下单)把订单放进队列,消费者(处理线程)从队列取。高峰期订单堆积在队列里,用户下单后要等半天才能看到结果,QPS 死活上不去。
🚀 王二的 “龟速” 秒杀代码
秒杀生产者:用户秒杀下单1
秒杀生产者:用户秒杀下单2
秒杀生产者:用户秒杀下单3
秒杀生产者:用户秒杀下单4
秒杀生产者:用户秒杀下单5
秒杀生产者:用户秒杀下单6
秒杀生产者:用户秒杀下单7
秒杀生产者:用户秒杀下单8
秒杀生产者:用户秒杀下单9
秒杀生产者:用户秒杀下单10
秒杀生产者:用户秒杀下单11
秒杀生产者:用户秒杀下单12
秒杀生产者:用户秒杀下单13
秒杀生产者:用户秒杀下单14
秒杀生产者:用户秒杀下单15
运行结果:订单堆积,处理慢如蜗牛
控制台里,生产者疯狂下单,消费者慢悠悠处理,订单堆积在队列里,1000 个订单要 20 秒才处理完,QPS 只有 50—— 这就是 “存储型队列” 的瓶颈:订单先存再处理,中间多了一道 “中转”,秒杀要的是 “即时性”,这道中转就是拖慢速度的元凶。
二、用 SynchronousQueue 改造:无存储,直接传递,QPS 翻倍
“SynchronousQueue 是个‘空队列’,没有任何存储容量,” 哇哥敲着代码解释,“生产者放订单(put)必须等消费者来取,消费者取订单(take)必须等生产者来放 —— 相当于订单直接从用户手里交到处理线程手里,没有中间堆积,响应自然快。”
‼️ 改造后的秒杀系统(QPS 翻倍)

package cn.tcmeta.blockingqueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
/**
* @author: laoren
* @description: // 秒杀系统——SynchronousQueue版(QPS翻倍)
* @version: 1.0.0
*/
public class SeckillSystemFast {
// 核心:SynchronousQueue,无存储,订单直接传递
static SynchronousQueue<Integer> orderQueue = new SynchronousQueue<>();
// 消费者线程池:扩容到10个线程,应对秒杀流量
static ExecutorService consumerPool = Executors.newFixedThreadPool(10);
static class SeckillProducer implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 1000; i++) {
try {
// put:必须等消费者取走订单才返回,无中间存储
orderQueue.put(i);
System.out.println(Thread.currentThread().getName() + ":用户秒杀下单" + i + "(直接交给处理线程)");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class SeckillConsumer implements Runnable {
@Override
public void run() {
while (true) {
try {
int orderId = orderQueue.take(); // 等生产者放订单
Thread.sleep(50); // 业务耗时不变
System.out.println(Thread.currentThread().getName() + ":处理秒杀订单" + orderId);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
public static void main(String[] args) {
// 启动10个消费者线程(比之前多,匹配秒杀流量)
for (int i = 0; i < 10; i++) {
consumerPool.submit(new SeckillConsumer());
}
// 启动生产者
new Thread(new SeckillProducer(), "秒杀生产者").start();
// 等待处理完成(只需10秒,比之前少一半)
try {
Thread.sleep(10000);
consumerPool.shutdownNow();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("秒杀订单处理完成,QPS翻倍!");
}
}
执行结果:
秒杀生产者:用户秒杀下单1000(直接交给处理线程)
pool-1-thread-5:处理秒杀订单991
pool-1-thread-3:处理秒杀订单992
pool-1-thread-1:处理秒杀订单993
pool-1-thread-7:处理秒杀订单995
pool-1-thread-10:处理秒杀订单994
pool-1-thread-6:处理秒杀订单996
pool-1-thread-9:处理秒杀订单997
pool-1-thread-8:处理秒杀订单999
pool-1-thread-2:处理秒杀订单998
pool-1-thread-4:处理秒杀订单1000
秒杀订单处理完成,QPS翻倍!
运行效果:10 秒处理完所有订单,QPS 破 1000
王二跑起来傻眼了:1000 个秒杀订单只用了 10 秒就处理完,QPS 直接涨到 1000+,用户下单后几乎秒出结果 —— 这就是 SynchronousQueue 的威力:无存储、直接传递,砍掉了 “订单中转” 的耗时,完美匹配秒杀的即时性需求。
三、阻塞队列的高级玩法:优先级、延时任务
解决了秒杀问题,哇哥又给王二讲了阻塞队列的另外两个常用玩法,都是工作中必用的。

🔰玩法 1:PriorityBlockingQueue——VIP 订单优先处理
“电商平台里,VIP 用户的订单要优先处理,普通用户的排后面,” 哇哥说,“PriorityBlockingQueue 能按优先级排序,完美解决这个需求。”
🎸 优先级订单代码示例
- PriorityOrder
package cn.tcmeta.blockingqueue;
/**
* @param priority 优先级:数字越大,优先级越高(1=普通,10=VIP)
* @author: laoren
* @description: // 订单类:实现Comparable,定义优先级
* @version: 1.0.0
*/
// 订单类:实现Comparable,定义优先级
record PriorityOrder(int orderId, int priority) implements Comparable<PriorityOrder> {
// 定义排序规则:高优先级先处理
@Override
public int compareTo(PriorityOrder o) {
return Integer.compare(o.priority, this.priority);
}
@Override
public String toString() {
return "订单" + orderId + "(优先级:" + priority + ")";
}
}
- PriorityBlockingQueueSample
package cn.tcmeta.blockingqueue;
import java.util.concurrent.PriorityBlockingQueue;
/**
* @author: laoren
* @description: // PriorityBlockingQueue实战:VIP订单优先
* @version: 1.0.0
*/
public class PriorityBlockingQueueSample {
static void main() throws InterruptedException {
PriorityBlockingQueue<PriorityOrder> queue = new PriorityBlockingQueue<>();
// 放入不同优先级的订单:普通、VIP、会员
queue.put(new PriorityOrder(1, 1)); // 普通用户
queue.put(new PriorityOrder(2, 10)); // VIP用户
queue.put(new PriorityOrder(3, 5)); // 会员用户
// 取出订单:按优先级排序
System.out.println("开始处理订单(按优先级):");
while (!queue.isEmpty()) {
System.out.println("处理:" + queue.take());
}
}
}
运行结果:VIP 订单先处理

✅ 玩法 2:DelayQueue—— 订单超时未支付自动取消
“用户下单后 15 分钟没付款,要自动取消订单,” 哇哥说,“用 DelayQueue 实现这个需求,比 Timer、ScheduledExecutorService 更简单,还不会丢任务。”

延时订单代码示例
package cn.tcmeta.blockingqueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* @param expireTime 订单过期时间
*/ // 延时订单:超时未支付自动取消
record DelayOrder(int orderId, long expireTime) implements Delayed {
DelayOrder(int orderId, long expireTime) {
this.orderId = orderId;
// 延迟时间(毫秒)
this.expireTime = System.currentTimeMillis() + expireTime;
}
// 剩余延迟时间(核心方法)
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
// 排序:先过期的订单先处理
@Override
public int compareTo(Delayed o) {
return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
}
// 取消订单逻辑
public void cancelOrder() {
System.out.println("订单" + orderId + "超时未支付,自动取消!");
}
}
- DelayQueueSample
package cn.tcmeta.blockingqueue;
import java.util.concurrent.DelayQueue;
/**
* @author: laoren
* @date: 2025/12/7 14:35
* @description: // DelayQueue实战:订单超时取消
* @version: 1.0.0
*/
public class DelayQueueSample {
public static void main(String[] args) throws InterruptedException {
DelayQueue<DelayOrder> queue = new DelayQueue<>();
// 放入3个延时订单:延迟2秒、1秒、3秒(模拟15分钟超时)
queue.put(new DelayOrder(1, 2000));
queue.put(new DelayOrder(2, 1000));
queue.put(new DelayOrder(3, 3000));
System.out.println("开始监控超时订单...");
// 处理超时订单:take()会阻塞,直到有订单过期
while (!queue.isEmpty()) {
DelayOrder order = queue.take();
order.cancelOrder();
}
}
}
运行结果:按过期时间取消订单
开始监控超时订单...
订单2超时未支付,自动取消!
订单1超时未支付,自动取消!
订单3超时未支付,自动取消!
四、阻塞队列选型指南:按场景选,不踩坑
哇哥给王二整理了一张 “选型表”,贴在显示器上,下次再也不用瞎选:


五、阻塞队列在并发编程中的核心应用
王二把哇哥的话总结成 “核心场景”,记在小本本上:
- 削峰填谷:用 ArrayBlockingQueue/LinkedBlockingQueue 做普通任务队列,缓解高峰期压力;
- 即时处理:用 SynchronousQueue 做秒杀、实时计算场景,提升 QPS;
- 优先级处理:用 PriorityBlockingQueue 实现 VIP 优先、紧急任务优先;
- 延时任务:用 DelayQueue 处理超时取消、定时提醒,替代 Timer;
- 线程池:作为线程池的任务队列,控制任务堆积,避免 OOM。
✔️ 哇哥的彩蛋:当年的 “翻车经历”
“我早年做电商,用 Timer 处理订单超时,” 哇哥笑着说,“结果一个订单抛异常,整个 Timer 线程崩了,所有超时订单都没处理,亏了好几万 —— 后来换成 DelayQueue,每个订单一个线程处理,再也没出过问题。”
📌 最后说句实在的

阻塞队列不是 “花架子”,而是 Java 并发编程的 “刚需工具”—— 你之前踩的丢单、OOM、响应慢的坑,本质都是没选对队列。
记住:普通场景用 ArrayBlockingQueue,秒杀用 SynchronousQueue,优先级用 PriorityBlockingQueue,延时用 DelayQueue,按场景选,比瞎写代码靠谱 10 倍。
关注我,下次咱们扒一扒阻塞队列的底层实现(ReentrantLock+Condition),让你不仅会用,还能讲透原理,面试时直接碾压面试官!



170万+

被折叠的 条评论
为什么被折叠?



