Java NIO核心组件是Buffer、Channel、Selector,三者协作:Buffer为带状态的数据容器,Channel为双向非阻塞传输通道,Selector为单线程事件调度器,共同实现高并发I/O。

Java NIO 的核心组件就三个:Buffer、Channel、Selector。它们不是并列关系,而是各司其职、环环相扣的一套协作机制——Buffer 是数据容器,Channel 是传输管道,Selector 是事件调度员。理解它们的关键不在于背定义,而在于看清谁负责存、谁负责运、谁负责盯梢。
Buffer:数据必须经过的“中转站”
所有 NIO 操作都绕不开 Buffer。它不是普通数组,而是一个带状态的内存块,有 capacity(容量)、position(当前位置)、limit(读写边界)三个关键属性。写数据时 position 递增;写完必须调用 flip() 才能切换为读模式——此时 position 归零、limit 设为刚才的 position;读完若要复用,调用 clear() 重置状态。
常见误区是忘记 flip(),结果 write() 写出空内容。推荐优先使用 ByteBuffer.allocateDirect(1024) 创建堆外缓冲区,避免 JVM 堆内存拷贝,尤其适合高频网络传输。
Channel:双向可非阻塞的“数据通道”
Channel 是对传统 Stream 的升级。它不单向,也不阻塞——SocketChannel 可同时读写,FileChannel 支持内存映射和文件锁。关键点在于:Channel 必须配合 Buffer 工作,不能直接操作字节;且只有继承自 SelectableChannel(如 SocketChannel、ServerSocketChannel)的通道才能注册到 Selector。
使用前务必调用 configureBlocking(false) 切换为非阻塞模式,否则 Selector 无法对其生效。例如:
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
Selector:单线程管理成千上万连接的“总控台”
Selector 是 NIO 实现高并发的基石。它本身不干活,只负责轮询注册在其上的 Channel 是否就绪(如 OP_ACCEPT、OP_READ、OP_WRITE)。一次 select() 调用返回后,遍历 selectedKeys() 就能知道哪些 Channel 有事要办,再分发处理。
注意三点:
• 一个 Selector 可管理多个 Channel,但每个 Channel 同一时刻只能注册在一个 Selector 上;
• 注册后需持续调用 select() 或 selectNow(),不能注册一次就不管;
• 处理完某个 key 后,必须手动从 selectedKeys 集合中 remove,否则下次 select 会重复返回。
三者协作的真实流程
以服务端接收客户端数据为例:
- ServerSocketChannel 接收到新连接,触发 OP_ACCEPT → Selector 通知
- 创建对应的 SocketChannel,设为非阻塞,并注册 OP_READ 到同一 Selector
- 当该 SocketChannel 有数据到达,触发 OP_READ → Selector 通知
- 分配 ByteBuffer,调用 channel.read(buffer) 将数据读入缓冲区
- buffer.flip() 后解析内容,处理完再 buffer.clear() 准备下一轮
整个过程,一个线程+一个 Selector 就能串起所有动作,不再需要为每个连接单独开线程。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










