导读:本期聚焦于小伙伴创作的《怎么利用 NIO 的 Pipe 实现同一个 JVM 内不同线程间的高性能内存级单向流通信》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《怎么利用 NIO 的 Pipe 实现同一个 JVM 内不同线程间的高性能内存级单向流通信》有用,将其分享出去将是对创作者最好的鼓励。

在 Java NIO 里,Pipe 是一个位于同一 JVM 内部的单向数据通道,由一个可写的 SinkChannel 和一个可读的 SourceChannel 组成。它非常适合用来在线程之间传递字节流,而且底层通常基于内存循环缓冲实现,不需要走网络协议栈,因此性能很高。

怎么利用 NIO 的 Pipe 实现同一个 JVM 内不同线程间的高性能内存级单向流通信

一、Pipe 的基本结构

Pipe 通过 Pipe.open() 创建,得到的两个通道分别负责写入和读取:

  • SinkChannel:只能写,生产者线程往里面塞数据
  • SourceChannel:只能读,消费者线程从里面取数据

由于是单向的,如果需要双向通信,就要创建两个 Pipe。另外,Pipe 本身线程安全程度有限,一般建议一个写线程、一个读线程,避免多写或多读造成混乱。

二、简单使用示例

下面演示一个生产者线程写数据、消费者线程读数据的完整例子:

import java.nio.ByteBuffer;
import java.nio.channels.Pipe;

public class PipeDemo {
    public static void main(String[] args) throws Exception {
        // 打开一个 Pipe
        Pipe pipe = Pipe.open();
        // 获取写通道和读通道
        Pipe.SinkChannel sink = pipe.sink();
        Pipe.SourceChannel source = pipe.source();

        // 生产者线程
        Thread writer = new Thread(() -> {
            try {
                ByteBuffer buf = ByteBuffer.allocate(1024);
                for (int i = 0; i < 5; i++) {
                    buf.clear();
                    String msg = "msg-" + i;
                    buf.put(msg.getBytes());
                    buf.flip();
                    // 写入 sink 通道
                    while (buf.hasRemaining()) {
                        sink.write(buf);
                    }
                }
                // 写完关闭 sink
                sink.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        // 消费者线程
        Thread reader = new Thread(() -> {
            try {
                ByteBuffer buf = ByteBuffer.allocate(1024);
                int len;
                // 从 source 通道读取
                while ((len = source.read(buf)) > 0) {
                    buf.flip();
                    byte[] data = new byte[buf.remaining()];
                    buf.get(data);
                    System.out.println("read: " + new String(data));
                    buf.clear();
                }
                source.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        writer.start();
        reader.start();
        writer.join();
        reader.join();
    }
}

三、和 BlockingQueue 的对比

很多开发者习惯用 BlockingQueue 做线程间通信,那 Pipe 有什么不同?

对比项PipeBlockingQueue
通信模型流式字节对象或消息块
底层实现内存循环缓冲数组或链表加锁
适用场景连续字节流离散任务或数据块

如果你的数据是连续字节流,比如序列化后的对象、日志流,Pipe 会更自然。如果是离散任务,BlockingQueue 更简单。

四、常见注意事项

1. 缓冲区满的问题

当消费者读得慢,SinkChannel 的写入会阻塞(或在非阻塞模式下返回 0)。生产方需要处理好这种情况,避免假死。

2. 正确关闭通道

写完数据后一定要关闭 SinkChannel,否则 SourceChannel.read 会一直阻塞,以为还有数据要来。

3. 不要多写多读

单个 Pipe 最好只配对一个写线程和一个读线程。多写需要自己加同步,多读可能丢数据。

五、小结

利用 NIO 的 Pipe 可以在同一个 JVM 内部以内存级方式实现高效的单向流通信。它比传统加锁队列更贴近流式处理,也更容易和 Channel 体系里的其他组件组合。只要注意关闭通道和控制读写线程数量,就能在生产者消费者场景中稳定发挥作用。

NIOPipe线程通信内存级流单向通道修改时间:2026-07-25 04:54:23

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。