Java NIO 高频面试考点汇总¶
一、NIO 三大核心组件¶
| 组件 | 作用 |
|---|---|
| Channel | 双向通道,类比 Stream,但可读可写 |
| Buffer | 数据容器,Channel 读写都经过 Buffer |
| Selector | 单线程监听多个 Channel 的事件(多路复用) |
经典模型:一个 Selector 线程管理多个 Channel,每个 Channel 注册感兴趣的事件。
二、Channel 的主要实现¶
FileChannel:文件读写,阻塞,不能切换非阻塞。SocketChannel/ServerSocketChannel:TCP。DatagramChannel:UDP。
三、Buffer 的核心概念¶
四个属性:
关键方法:
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put((byte) 1);
buf.flip(); // 写转读:limit = position, position = 0
buf.get();
buf.clear(); // 读转写:position = 0, limit = capacity(不真正清数据)
buf.compact(); // 把未读数据移到开头,继续写
flip 和 clear 的区别
flip():读之前调用,把 limit 设为当前 position,position 归零。clear():读之后调用,position 归零、limit = capacity,数据还在但被覆盖。rewind():只把 position 归零,limit 不变(重读)。
四、Selector 多路复用¶
Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
while (true) {
int ready = selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey k = it.next();
it.remove();
if (k.isReadable()) { ... }
else if (k.isWritable()) { ... }
}
}
四种事件:OP_READ、OP_WRITE、OP_CONNECT、OP_ACCEPT。
五、BIO vs NIO vs AIO¶
| BIO | NIO | AIO | |
|---|---|---|---|
| 模式 | 同步阻塞 | 同步非阻塞 | 异步非阻塞 |
| 流向 | 流式 | 缓冲式 | 缓冲式 |
| 核心 | Stream | Channel+Buffer+Selector | Future/Callback |
| 适用 | 连接少、短连接 | 连接多、轻量 | 连接多、操作重 |
六、零拷贝¶
传统数据传输:磁盘 → 内核缓冲区 → 用户态 → Socket 缓冲区 → 协议栈,4 次拷贝、4 次上下文切换。
NIO 的 FileChannel.transferTo() 使用 sendfile 系统调用,数据直接在内核态从文件描述符传到 Socket,CPU 不参与。Netty 的 FileRegion 也是这个原理。
七、Netty 为什么快¶
- 基于 NIO,主从 Reactor 线程模型。
- 零拷贝:
CompositeByteBuf、transferTo。 - 内存池:
ByteBuf池化减少 GC。 - 高效编解码。
高频追问
- 为什么 FileChannel 不能非阻塞?文件 IO 本来就没有"等待连接"的概念。
- Selector 在 Linux 上用 epoll,Windows 上用 select/POLL。epoll 比 select 快在:无 FD 上限、回调而非轮询。