SynchronousQueue 是 Java 并发包(java.util.concurrent)中的一个特殊阻塞队列,它 不存储任何元素,而是直接在生产者和消费者之间传递数据。
目录
(1) TransferStack.transfer()(非公平模式)
(2) TransferQueue.transfer()(公平模式)
核心特点
-
无容量:
SynchronousQueue没有内部存储空间,每个put()操作必须等待一个take()操作,反之亦然。 -
直接传递:数据直接从生产者传递给消费者,不经过队列缓存。
-
公平性可选:
-
非公平模式(默认):采用栈(LIFO)方式匹配生产者和消费者,吞吐量较高。
-
公平模式:采用队列(FIFO)方式匹配,保证公平性但性能稍低。
-
-
适用于高并发任务分发:如线程池(
Executors.newCachedThreadPool默认使用SynchronousQueue)。
核心方法
| 方法 | 说明 |
|---|---|
put(E e) | 阻塞,直到有消费者取走数据 |
offer(E e) | 尝试放入数据,如果没有消费者则立即返回 false |
offer(E e, long timeout, TimeUnit unit) | 带超时的 offer() |
take() | 阻塞,直到有生产者放入数据 |
poll() | 尝试取数据,如果没有生产者则立即返回 null |
poll(long timeout, TimeUnit unit) | 带超时的 poll() |
isEmpty() | 始终返回 true(因为没有存储元素) |
size() | 始终返回 0 |
适用场景
-
线程池任务调度
Executors.newCachedThreadPool()使用SynchronousQueue,因为:-
新任务到来时,如果有空闲线程,则立即执行;
-
如果没有空闲线程,则创建新线程(适用于短任务高并发场景)。
-
-
生产者-消费者直接通信
适用于需要严格同步的生产者-消费者模型,如:-
实时任务分发;
-
线程间直接传递数据,避免缓存。
-
-
替代
CountDownLatch或Exchanger
在某些场景下,可以用SynchronousQueue实现线程间的同步交换。
对比其他队列
| 队列 | 存储元素 | 阻塞行为 | 适用场景 |
|---|---|---|---|
SynchronousQueue | ❌ 不存储 | put() 和 take() 必须配对 | 高并发任务分发 |
ArrayBlockingQueue | ✅ 有界数组 | 队列满时阻塞 put(),空时阻塞 take() | 固定大小的缓冲队列 |
LinkedBlockingQueue | ✅ 可选有界/无界链表 | 同 ArrayBlockingQueue | 通用任务队列 |
PriorityBlockingQueue | ✅ 无界优先级堆 | 仅 take() 可能阻塞 | 优先级任务调度 |
核心实现原理
SynchronousQueue 的底层实现基于两种不同的数据结构,取决于构造时选择的公平性:
(1) TransferStack(非公平模式,栈结构)
-
采用 LIFO(后进先出) 策略,新来的线程可能优先匹配。
-
使用 CAS(Compare-And-Swap) 进行无锁并发控制。
-
每个节点
SNode包含:-
volatile SNode next:栈中的下一个节点 -
volatile SNode match:匹配的节点 -
volatile Thread waiter:等待的线程 -
Object item:传输的数据 -
int mode:模式(REQUEST/DATA,表示take或put)
-
(2) TransferQueue(公平模式,队列结构)
-
采用 FIFO(先进先出) 策略,保证公平性。
-
同样使用 CAS 进行线程安全控制。
-
每个节点
QNode包含:-
volatile QNode next:队列中的下一个节点 -
volatile Object item:传输的数据 -
volatile Thread waiter:等待的线程 -
boolean isData:区分生产者(put)和消费者(take)
-
关键数据结构
TransferStack 节点结构
static final class SNode {
volatile SNode next; // 栈中的下一个节点
volatile SNode match; // 匹配的节点
volatile Thread waiter; // 等待的线程
Object item; // 传输的数据
int mode; // 模式(REQUEST/PUT/TAKE)
}
TransferQueue 节点结构
static final class QNode {
volatile QNode next; // 队列中的下一个节点
volatile Object item; // 传输的数据
volatile Thread waiter; // 等待的线程
final boolean isData; // 区分生产者/消费者
}
核心操作机制
SynchronousQueue 的核心操作(put/take)都通过 transfer 方法实现:
(1) 生产者(put 操作)
-
如果当前栈/队列为空,或已有其他生产者在等待:
-
将当前线程封装成
SNode/QNode并加入栈/队列。 -
进入阻塞状态(
LockSupport.park())。
-
-
如果遇到匹配的消费者(
take操作):-
直接交换数据(
item)。 -
唤醒消费者线程(
LockSupport.unpark(waiter))。
-
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
(2) 消费者(take 操作)
-
如果当前栈/队列为空,或已有其他消费者在等待:
-
将当前线程封装成
SNode/QNode并加入栈/队列。 -
进入阻塞状态(
LockSupport.park())。
-
-
如果遇到匹配的生产者(
put操作):-
直接获取数据(
item)。 -
唤醒生产者线程(
LockSupport.unpark(waiter))。
-
public E take() throws InterruptedException {
E e = transferer.transfer(null, false, 0);
if (e != null)
return e;
Thread.interrupted();
throw new InterruptedException();
}
关键代码分析
(1) TransferStack.transfer()(非公平模式)
E transfer(E e, boolean timed, long nanos) {
SNode s = null;
int mode = (e == null) ? REQUEST : DATA; // REQUEST=take, DATA=put
for (;;) {
SNode h = head;
if (h == null || h.mode == mode) { // 栈空或相同模式(无匹配)
if (timed && nanos <= 0) return null; // 超时
s = new SNode(e, h, mode); // 创建新节点
if (casHead(h, s)) { // CAS 更新栈顶
SNode m = awaitFulfill(s, timed, nanos); // 阻塞等待匹配
if (m == s) return null; // 被取消
return (E) ((mode == REQUEST) ? m.item : s.item); // 返回匹配数据
}
} else if (casHead(h, s = h.next)) { // 匹配成功
LockSupport.unpark(h.waiter); // 唤醒匹配线程
return (E) ((mode == REQUEST) ? h.item : s.item);
}
}
}
(2) TransferQueue.transfer()(公平模式)
E transfer(E e, boolean timed, long nanos) {
QNode s = null;
boolean isData = (e != null); // put=true, take=false
for (;;) {
QNode t = tail, h = head;
if (t == null || h == null) continue; // 未初始化
if (h == t || t.isData == isData) { // 队列空或相同模式
QNode node = new QNode(e, isData);
if (!casTail(t, node)) continue; // CAS 入队
Object x = awaitFulfill(node, timed, nanos); // 阻塞等待
if (x == node) return null; // 被取消
return (E) x;
} else { // 匹配成功
QNode m = h.next;
LockSupport.unpark(m.waiter); // 唤醒匹配线程
return (E) m.item;
}
}
}
性能特点
-
高吞吐量:直接传递,无存储开销。
-
低延迟:生产者与消费者直接交互,减少中间步骤。
-
公平模式 vs 非公平模式:
-
非公平模式(栈):吞吐量更高,但可能导致线程饥饿。
-
公平模式(队列):保证先到先服务,减少饥饿问题,但吞吐量略低。
-
更多java集合底层详解,请查看专栏 Java基础之集合专栏
HashMap详解 HashLink详解 ArrayList详解 CopyOnWriteArrayList详解 HashSet详解 LinkedHashMap详解 LinkedHashSet详解 TreeSet详解 TreeMap详解 ConcurrentHashMap详解 PriorityBlockingQueue 详解 PriorityQueue 详解 ArrayDeque 详解 java集合详解 - LinkedBlockingQueue 详解
1102

被折叠的 条评论
为什么被折叠?



