没有容量,生产者和消费者必须手拉手直接交易!像快递员和收件人当面交接。
一、SynchronousQueue是什么?
核心特点
- 容量为0:不存储元素
- 直接交付:生产者阻塞,直到消费者取走
- 配对模式:生产者和消费者必须同时到达
生活类比
普通队列像快递柜📦:
- 快递员放进柜子
- 收件人随时来取
- 柜子存储包裹
SynchronousQueue像当面交接🤝:
- 快递员等收件人
- 收件人等快递员
- 必须同时在场
二、基本使用
SynchronousQueue<String> queue = new SynchronousQueue<>();
// 生产者
new Thread(() -> {
try {
System.out.println("生产者准备put");
queue.put("数据"); // 阻塞,直到有消费者take
System.out.println("生产者put成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(2000); // 生产者等待2秒
// 消费者
new Thread(() -> {
try {
System.out.println("消费者准备take");
String data = queue.take(); // 取走数据
System.out.println("消费者take: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
输出:
生产者准备put
(等待2秒)
消费者准备take
生产者put成功
消费者take: 数据
三、公平模式 vs 非公平模式
非公平模式(默认)
SynchronousQueue<String> queue = new SynchronousQueue<>();
// 后来的线程可能先匹配
公平模式
SynchronousQueue<String> queue = new SynchronousQueue<>(true);
// FIFO,先来先服务
四、应用场景
场景1:CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(
0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>() // ← 这里!
);
}
作用: 任务来了,没有空闲线程就创建新线程
场景2:任务交接
public class TaskHandoff {
private final SynchronousQueue<Task> queue = new SynchronousQueue<>();
// 生产者提交任务
public void submitTask(Task task) throws InterruptedException {
System.out.println("提交任务,等待工作线程");
queue.put(task); // 阻塞,直到工作线程接收
System.out.println("任务已被接收");
}
// 工作线程获取任务
public Task getTask() throws InterruptedException {
System.out.println("工作线程等待任务");
return queue.take(); // 阻塞,直到有任务
}
}
场景3:请求-响应模式
public class RequestResponse {
private final SynchronousQueue<String> requestQueue = new SynchronousQueue<>();
private final SynchronousQueue<String> responseQueue = new SynchronousQueue<>();
// 客户端
public String request(String req) throws InterruptedException {
requestQueue.put(req); // 发送请求
return responseQueue.take(); // 等待响应
}
// 服务端
public void serve() throws InterruptedException {
while (true) {
String req = requestQueue.take(); // 接收请求
String resp = process(req); // 处理
responseQueue.put(resp); // 发送响应
}
}
}
五、实现原理(简化)
TransferQueue内部
abstract class Transferer<E> {
// mode: REQUEST(消费者)或 DATA(生产者)
abstract E transfer(E e, boolean timed, long nanos);
}
// 生产者
queue.put(item) → transfer(item, false, 0)
// 消费者
queue.take() → transfer(null, false, 0)
匹配过程:
1. 生产者到达:放入栈,等待消费者
2. 消费者到达:从栈中找到生产者,配对
3. 数据传递,双方唤醒
六、对比其他队列
| 特性 | SynchronousQueue | ArrayBlockingQueue | LinkedBlockingQueue |
|---|---|---|---|
| 容量 | 0 | 有界 | 可选 |
| 存储 | ❌ 不存储 | ✅ 存储 | ✅ 存储 |
| 阻塞 | 双向阻塞 | 单向阻塞 | 单向阻塞 |
| 性能 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 场景 | 直接交付 | 缓冲 | 缓冲 |
七、面试高频问答💯
Q: SynchronousQueue的容量是多少?
A: 0,不存储元素。
Q: SynchronousQueue适合什么场景?
A:
- 任务直接交付(CachedThreadPool)
- 生产消费配对
- 请求响应模式
Q: SynchronousQueue的put和take会阻塞吗?
A: 会! 直到另一方到达。
下一篇→ 手写无锁栈和队列🔓