LinkedTransferQueue是Java并发包中提供的无界阻塞队列,它的transfer方法可以实现生产者将数据直接传递给等待的消费者,不需要在队列中暂存数据,也就是零容量传递的效果,非常适合需要严格同步的生产者消费者场景。

LinkedTransferQueue与transfer机制基础
LinkedTransferQueue继承自AbstractQueue,同时实现了TransferQueue接口,和其他阻塞队列相比,它新增了几个和直接传递相关的方法,其中transfer是最核心的方法。transfer方法的作用是:生产者调用该方法放入元素时,会一直阻塞直到有消费者来取走这个元素,整个过程元素不会在队列中停留,实现零容量传递。
我们对比下transfer和普通的put方法的区别:
| 方法 | 阻塞逻辑 | 是否暂存元素 |
|---|---|---|
| put | 无界队列不会阻塞,元素直接入队 | 是,元素会存在队列中 |
| transfer | 直到有消费者取走元素才会返回 | 否,元素直接传递给消费者 |
零容量传递的实现原理
transfer方法的实现逻辑可以简单概括为:当生产者调用transfer放入元素时,首先会检查当前是否有等待的消费者节点,如果有就直接把元素交给消费者,唤醒消费者线程;如果没有等待的消费者,生产者线程会把当前元素包装成节点,然后阻塞等待,直到有消费者来取走这个节点中的元素才会被唤醒。
整个过程没有元素在队列中缓冲,完全是一手交钱一手交货的同步传递,所以不需要队列有容量,也就是零容量传递。
生产者消费者零容量传递实现示例
下面我们通过一个完整的示例来演示如何使用transfer方法实现生产者消费者间的零容量传递,示例中生产者生产一个数据后必须等消费者取走才能继续生产下一个,消费者取数据时必须等生产者生产才能取到。
生产者线程实现
生产者线程循环生产数据,每次生产后调用transfer方法传递数据,阻塞直到消费者取走:
import java.util.concurrent.LinkedTransferQueue;
public class Producer implements Runnable {
private LinkedTransferQueue<String> queue;
private int produceCount;
public Producer(LinkedTransferQueue<String> queue, int produceCount) {
this.queue = queue;
this.produceCount = produceCount;
}
@Override
public void run() {
try {
for (int i = 1; i <= produceCount; i++) {
String data = "生产数据-" + i;
System.out.println(Thread.currentThread().getName() + " 开始生产:" + data);
// 调用transfer方法,阻塞直到消费者取走数据
queue.transfer(data);
System.out.println(Thread.currentThread().getName() + " 生产完成,数据已被消费者取走");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().getName() + " 被中断");
}
}
}
消费者线程实现
消费者线程循环从队列中取数据,因为生产者是零容量传递,所以消费者调用take方法时会阻塞直到生产者生产数据:
import java.util.concurrent.LinkedTransferQueue;
public class Consumer implements Runnable {
private LinkedTransferQueue<String> queue;
private int consumeCount;
public Consumer(LinkedTransferQueue<String> queue, int consumeCount) {
this.queue = queue;
this.consumeCount = consumeCount;
}
@Override
public void run() {
try {
for (int i = 1; i <= consumeCount; i++) {
// 阻塞等待生产者传递数据
String data = queue.take();
System.out.println(Thread.currentThread().getName() + " 消费到数据:" + data);
// 模拟消费耗时
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println(Thread.currentThread().getName() + " 被中断");
}
}
}
测试主类
主类中创建LinkedTransferQueue实例,启动生产者和消费者线程,验证零容量传递效果:
import java.util.concurrent.LinkedTransferQueue;
public class TransferTest {
public static void main(String[] args) {
// 创建LinkedTransferQueue实例,不需要设置容量
LinkedTransferQueue<String> queue = new LinkedTransferQueue<>();
// 创建生产者和消费者,生产3条数据,消费3条数据
Producer producer = new Producer(queue, 3);
Consumer consumer = new Consumer(queue, 3);
// 启动消费者线程
Thread consumerThread = new Thread(consumer, "消费者线程");
consumerThread.start();
// 启动生产者线程
Thread producerThread = new Thread(producer, "生产者线程");
producerThread.start();
}
}
运行结果说明
运行上述代码,输出结果类似如下:
消费者线程 消费到数据:生产数据-1
生产者线程 开始生产:生产数据-1
生产者线程 生产完成,数据已被消费者取走
生产者线程 开始生产:生产数据-2
消费者线程 消费到数据:生产数据-2
生产者线程 生产完成,数据已被消费者取走
生产者线程 开始生产:生产数据-3
消费者线程 消费到数据:生产数据-3
生产者线程 生产完成,数据已被消费者取走
从结果可以看到,生产者每生产一个数据,必须等消费者取走之后才会生产下一个,整个过程没有数据在队列中缓冲,实现了零容量传递的效果。
使用注意事项
- transfer方法是阻塞方法,如果消费者一直不启动或者异常退出,生产者线程会一直阻塞,实际使用中需要做好线程中断处理。
- 如果需要超时机制,可以使用
tryTransfer方法,该方法可以设置超时时间,超时后如果还没有消费者取走数据就会返回false。 - LinkedTransferQueue是无界队列,但是使用transfer方法时不会用到队列的容量特性,所以即使队列无界也不影响零容量传递的效果。
LinkedTransferQueuetransfer机制生产者消费者零容量传递修改时间:2026-07-23 15:03:34