java nio 中的 pipe 用于在同一进程内的两个线程之间进行通信,其核心机制是创建一个包含 sourcechannel 和 destinationchannel 的管道对象。要使用它,只需调用 pipe.open() 获取实例,然后在发送端向 destination().write() 写入数据,在接收端从 source().read() 读取数据即可。

如何创建并初始化 Pipe 实例
创建 Pipe 实例非常简单,直接调用静态方法 Pipe.open() 即可返回一个已打开的管道对象。该操作会分配底层的操作系统资源(如 Unix 域套接字或 Windows 命名管道),因此在使用完毕后必须关闭。如果不需要了,应调用 pipe.close() 来释放资源,避免内存泄漏。

import java.nio.channels.Pipe;
public class PipeDemo {
public static void main(String[] args) throws Exception {
// 1. 创建 Pipe 实例
Pipe pipe = Pipe.open();
try {
// 后续操作...
} finally {
// 2. 确保关闭资源
pipe.close();
}
}
}
上述代码展示了最基础的创建与关闭流程。在实际应用中,通常会将 Pipe 的创建放在线程启动之前,以便两个线程能够共享同一个管道引用。需要注意的是,Pipe.open() 可能会抛出 IOException,因此在生产环境中需要妥善处理异常。
立即学习“Java免费学习笔记(深入)”;
如何在发送端和接收端之间传输数据
数据传输的核心在于分别获取管道的两端通道:destination() 用于写入,source() 用于读取。发送线程将 ByteBuffer 中的数据写入 destination,接收线程则从 source 中读取。由于 Pipe 是阻塞式的,如果缓冲区满或为空,读写操作会挂起直到条件满足。这种同步机制简化了并发编程,无需额外的锁或队列管理。

import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
import java.nio.charset.StandardCharsets;
public class PipeTransferDemo {
public static void main(String[] args) throws Exception {
Pipe pipe = Pipe.open();
// 发送端线程
Thread sender = new Thread(() -> {
try {
String data = "Hello from Sender";
ByteBuffer buffer = ByteBuffer.wrap(data.getBytes(StandardCharsets.UTF_8));
pipe.destination().write(buffer);
} catch (Exception e) {
e.printStackTrace();
}
});
// 接收端线程
Thread receiver = new Thread(() -> {
try {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = pipe.source().read(buffer);
if (bytesRead > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
System.out.println("Received: " + new String(bytes, StandardCharsets.UTF_8));
}
} catch (Exception e) {
e.printStackTrace();
}
});
sender.start();
receiver.start();
sender.join();
receiver.join();
pipe.close();
}
}
在这个示例中,发送线程将字符串转换为字节数组并包装成 ByteBuffer,然后调用 write()。接收线程分配一个足够大的缓冲区,调用 read() 获取数据。注意,read() 返回的是实际读取的字节数,如果返回 -1 表示流结束。由于 Pipe 是单生产者-单消费者模型,这种简单的读写模式足以保证数据的有序性和完整性。
当缓冲区容量不足时 Pipe 的行为是什么
当发送端写入的数据量超过管道内部缓冲区的剩余容量时,destination().write() 方法会阻塞当前线程,直到接收端读取部分数据释放出空间为止。同样,如果接收端尝试读取但管道中没有数据,source().read() 也会阻塞,直到发送端写入新数据。这种背压机制确保了数据不会丢失,也不会导致内存溢出。开发者无需手动处理流量控制,NIO 框架会自动协调两端的速率。


















