SynchronousQueue的公平模式使用FIFO队列(TransferQueue),按到达顺序匹配;非公平模式使用LIFO栈(TransferStack),仅匹配栈顶,吞吐更高但可能饥饿。

SynchronousQueue 的公平模式与非公平模式,核心区别不在“锁是否公平”,而在于 Waiter 队列的组织结构和线程匹配顺序——这直接决定了谁先被唤醒、谁先完成配对。
公平模式:Waiter 按 FIFO 排队,匹配从队首开始
启用公平模式(new SynchronousQueue(true))后,内部使用 TransferQueue,所有阻塞的线程(无论是调用 put() 还是 take())统一进入一个单向链表队列,按到达时间严格排序:
- 新线程入队时追加到队尾,不会跳过前面任何等待者
- 匹配操作总是从
head开始扫描,优先尝试与队首等待者配对(比如队首是take,新来put就立即匹配它) - 每个节点(
QNode)只存线程引用和操作类型,不存数据;匹配成功后节点即被移除 - 因需维护头尾指针 + CAS 更新链表,高并发下易出现竞争,导致部分 CAS 失败重试,间接拉低吞吐
非公平模式:Waiter 堆叠成栈,匹配只看栈顶
默认构造(或传 false)启用 TransferStack,Waiter 以 LIFO 方式组织在栈中:
- 新线程直接压入栈顶,不检查队列长度或等待时长
- 匹配逻辑始终聚焦栈顶节点:若栈顶是反向操作(如当前
put遇到栈顶为take),立刻配对并弹出两者 - 支持自旋优化——新线程会先轻量级检查栈顶是否可配对,失败才压栈,减少上下文切换
- 栈操作(push/pop)局部性好、CAS 冲突少,吞吐更高,但早来的线程可能长期压在栈底,得不到服务
Waiter 队列行为不可见,但影响真实调度
无论哪种模式,SynchronousQueue 都不保存元素值,Waiter 队列里只记录线程和匹配状态。你无法通过 size()、isEmpty() 或 iterator() 观察它——这些方法一律返回 0 或抛异常。判断实际用的是哪一种,只能:
立即学习“Java免费学习笔记(深入)”;
- 看构造参数:
true→ FIFO 队列,false或无参 → LIFO 栈 - 运行时反射检查
transferer字段:instanceof TransferQueue表示公平,instanceof TransferStack表示非公平
选择依据:延迟敏感选非公平,确定性要求选公平
如果系统追求高吞吐、能容忍个别线程短时饥饿(如高频任务分发),非公平模式更合适;若业务逻辑强依赖请求处理顺序(如金融指令、日志保序),公平模式可避免“后来居上”,确保等待最久的线程优先获得服务。


















