零拷贝解决传统BIO文件复制中CPU多次拷贝的性能浪费问题,Java通过FileChannel.transferTo()在内核态直接传输数据;多路复用解决BIO高并发下线程爆炸问题,Java通过Selector封装epoll等系统调用,单线程管理海量连接。

面试中讲 NIO 的零拷贝和多路复用,关键不是背定义,而是说清“它解决了什么问题”和“Java 里怎么体现”。下面分两块直接讲清楚。
零拷贝:省掉内核和用户空间之间那几次搬数据
传统 BIO 文件复制要走四步:磁盘→内核缓冲区→用户缓冲区→内核缓冲区→网卡。中间两次 CPU 拷贝纯属浪费,尤其大文件时耗 CPU、占带宽。
NIO 的 FileChannel.transferTo() 就是零拷贝的落地方式——它让操作系统直接在内核态把数据从文件描述符传到 socket 描述符,跳过用户空间。前提是底层支持(比如 Linux 的 sendfile 系统调用)。
- 代码里不用 new byte[],不调 read() + write(),就一行 transferTo(0, size, targetChannel)
- 注意:transferTo 不一定总能零拷贝。如果目标 Channel 不支持(如某些管道),JDK 会自动退化为普通拷贝
- 适用场景:静态资源服务、大文件下载、日志归档等高吞吐传输
多路复用:一个线程盯住成千上万个连接
不是 Java 自己发明的,而是封装了操作系统的 IO 多路复用机制(Linux 是 epoll,Windows 是 select)。核心是 Selector —— 它让单个线程可以轮询多个 Channel 的状态(可读、可写、已连接)。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
BIO 是“来一个连接开一个线程”,1 万连接就要 1 万线程;NIO 是“一个 Selector 管一堆 Channel”,线程数可控,上下文切换少,适合高并发短连接场景(如 IM、网关)。
- 关键三步:Channel 注册到 Selector(必须是非阻塞模式)、调 select() 等待事件、遍历 selectedKeys() 处理就绪 Channel
- Selector 不是万能的:它只通知“有数据可读”,真正 read() 还得你自己做——所以 NIO 是同步非阻塞,不是异步
- 别混淆:多路复用 ≠ 多线程,它是用更少线程做更多事,靠的是事件驱动 + 非阻塞 + 缓冲区协作
讲完这两点,可以顺带提一句:Netty 就是站在 NIO 肩膀上做的封装,把 Selector、Buffer、线程模型、内存池这些细节都包圆了,让开发者专注业务逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










