SynchronousQueue不存储元素,每个put需等待take,适合线程间直接数据交换。示例中生产者调用put后阻塞,消费者调用take后完成传递,二者同步协作。常用于newCachedThreadPool线程池,适用于任务即时处理场景,使用时需配对线程操作并处理中断,避免阻塞。

SynchronousQueue 是 Java 并发包中一个特殊的阻塞队列,它不存储元素。每个 put 操作必须等待另一个线程的 take 操作,反之亦然。这种“一对一交换”的特性使其非常适合用于两个线程之间直接传递数据,实现线程间的同步协作。
理解 SynchronousQueue 的工作机制
SynchronousQueue 不像其他队列那样持有数据。当你调用 put() 时,当前线程会阻塞,直到另一个线程调用 take() 来取走这个元素;同样地,如果一个线程先调用 take(),它也会一直阻塞,直到另一个线程执行 put()。这就像两个人面对面交接物品,必须同时在场才能完成传递。
这种机制天然适合实现线程间的数据交换,尤其是在生产者-消费者模式中只有一个生产者和一个消费者的情况下。
使用 SynchronousQueue 实现线程交换的步骤
下面是一个简单的例子,展示如何使用 SynchronousQueue 在两个线程之间交换字符串消息:
立即学习“Java免费学习笔记(深入)”;
- 创建一个 SynchronousQueue 实例
- 启动一个线程进行 put 操作
- 启动另一个线程进行 take 操作
- 观察两个线程如何通过队列完成数据传递
示例代码:
import java.util.concurrent.SynchronousQueue;
public class SynchronousQueueExample {
public Static void main(String[] args) {
SynchronousQueue<String> queue = new SynchronousQueue<>();
// 生产者线程
Thread producer = new Thread(() -> {
try {
System.out.println(“生产者准备发送数据…”);
queue.put(“Hello from Producer”);
System.out.println(“数据已发送”);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// 消费者线程
Thread consumer = new Thread(() -> {
try {
System.out.println(“消费者等待接收数据…”);
String data = queue.take();
System.out.println(“收到数据: ” + data);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
consumer.start();
producer.start();
} }
实际应用场景与注意事项
SynchronousQueue 常用于线程池中(如 Executors.newCachedThreadPool()),适用于任务提交频率波动大、工作线程生命周期短的场景。由于其不缓存任务,每个任务都需要立即有线程来处理。
使用时需要注意:
- 确保有配对的线程分别执行 put 和 take,否则线程将永久阻塞
- 务必处理 InterruptedException,避免中断信号被忽略
- 不适合用于多生产者多消费者高并发场景,容易造成线程竞争激烈
- 可用于实现更高级的同步结构,比如双线程协作计算
基本上就这些。SynchronousQueue 的设计目标就是让线程之间直接交接数据,而不是通过中间缓冲区。只要理解了这一点,就能合理地在需要强同步的场景中使用它。


