synchronousqueue公平模式本质是fifo线程配对机制,由transferqueue实现,不缓存数据、仅通过线程直接交接传递元素;新put入队尾,新take匹配队头,cas保障顺序,吞吐量略低于非公平模式。

SynchronousQueue 的公平模式本质是“先到先服务”的线程配对机制,底层由 TransferQueue 实现,不缓存数据、不占用内存空间,所有通信都依赖生产者与消费者线程的直接交接。
公平模式的核心行为特征
公平模式下,SynchronousQueue 表现为一个逻辑上的 FIFO 队列,但这个队列里存的不是数据元素,而是等待配对的线程节点。每个 put 或 take 操作都会生成一个节点,节点中保存当前线程引用(waiter)并进入阻塞状态,直到匹配成功。
- 新来的
put线程总是插入队尾,新来的take线程总是尝试与队头等待的put线程配对 - 配对成功后,被匹配的线程被唤醒,数据从生产者直接传给消费者,节点被清理(
waiter = null) - 没有“入队-出队”意义上的数据搬运,只有线程状态切换和引用传递
TransferQueue 的结构与状态流转
TransferQueue 维护 head 和 tail 两个原子引用指针,初始时二者指向同一个哨兵节点。每次操作都会构造新节点并 CAS 更新 tail;匹配则通过 CAS 修改 head 完成节点摘除。
- 节点入队:线程创建节点 → 设置
waiter = Thread.currentThread()→ CAS 将其追加到 tail 后 → 自旋若干次 → 调用LockSupport.park()阻塞 - 匹配触发:当一个
take操作到来,它会检查head.next是否存在等待的put节点;若存在,就尝试 CAS 唤醒该节点线程,并将自身携带的消费意图完成交接 - 匹配完成:被唤醒的
put线程恢复执行,返回数据;take线程拿到数据并返回;双方节点从队列中逻辑移除
公平性如何被保障
公平性不靠锁或全局计数器,而是由队列的 FIFO 结构天然保证:谁先来排队,谁就优先被后续到来的反向操作匹配。
- 多个
put线程依次调用,它们在队列中按调用顺序排列;后续任意一个take线程只会匹配最先进入的put节点(即head.next),不会跳过中间节点 - 即使有多个
take并发到达,它们也按到达顺序竞争匹配权,CAS 失败者继续向后查找或入队等待 - 这种“队尾入、队头出”的策略避免了饥饿,但比非公平模式(TransferStack)多一次链表遍历和更多 CAS 竞争,吞吐量略低
实际使用中的关键细节
构造时显式指定 fair = true 才启用 TransferQueue;默认构造函数使用的是非公平的 TransferStack。
- 所有阻塞方法(
put/take)在公平模式下严格遵循 FIFO 等待顺序,超时方法(offer(e, timeout)/poll(timeout))同样遵守,只是增加自旋+限时 park 逻辑 - 自旋次数受 CPU 核心数影响:
maxUntimedSpins = 512(双核及以上),避免立即阻塞带来的上下文切换开销 - 不支持
size()、isEmpty()、iterator()等方法,因为内部无真实元素存储,这些方法始终返回固定值或抛异常










