SynchronousQueue:零容量的交接站🎭

18 阅读2分钟

没有容量,生产者和消费者必须手拉手直接交易!像快递员和收件人当面交接。

一、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. 数据传递,双方唤醒

六、对比其他队列

特性SynchronousQueueArrayBlockingQueueLinkedBlockingQueue
容量0有界可选
存储❌ 不存储✅ 存储✅ 存储
阻塞双向阻塞单向阻塞单向阻塞
性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
场景直接交付缓冲缓冲

七、面试高频问答💯

Q: SynchronousQueue的容量是多少?

A: 0,不存储元素。

Q: SynchronousQueue适合什么场景?

A:

  • 任务直接交付(CachedThreadPool)
  • 生产消费配对
  • 请求响应模式

Q: SynchronousQueue的put和take会阻塞吗?

A: 会! 直到另一方到达。


下一篇→ 手写无锁栈和队列🔓