IO 与 NIO 性能对比
传统 IO(BIO)和 NIO 在设计模型和性能特点上有本质差异。
线程模型对比
传统 IO(阻塞)
Java
连接1 → 线程1(阻塞等待)
连接2 → 线程2(阻塞等待)
连接3 → 线程3(阻塞等待)
...
1000 连接 = 1000 线程
线程开销大,资源浪费
NIO(非阻塞)
Java
连接1 ─┐
连接2 ─┼→ Selector → 单线程(轮询处理)
连接3 ─┤
...
1000 连接 = 1 个线程 + Selector
线程开销小,高效管理
核心差异
| 特性 | 传统 IO | NIO |
|---|---|---|
| 模式 | 阻塞 | 非阻塞 |
| 线程模型 | 一连接一线程 | 单线程多连接 |
| 数据传输 | 字节流/字符流 | Buffer 缓冲区 |
| 通道方向 | 单向(InputStream/OutputStream) | 双向(Channel) |
| 多路复用 | 不支持 | Selector 支持 |
| 零拷贝 | 不支持 | FileChannel.transferTo 支持 |
文件操作性能
传统 IO 文件复制
Java
try (FileInputStream fis = new FileInputStream("src.txt");
FileOutputStream fos = new FileOutputStream("dst.txt")) {
byte[] buffer = new byte[8192];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
}
// 数据复制:磁盘 → 内核 → JVM → 内核 → 磁盘(4次)
NIO 零拷贝复制
Java
try (FileChannel src = new FileInputStream("src.txt").getChannel();
FileChannel dst = new FileOutputStream("dst.txt").getChannel()) {
dst.transferFrom(src, 0, src.size());
}
// 数据复制:磁盘 → 内核 → 磁盘(2次),减少 CPU 参与
零拷贝:减少数据在 JVM 和内核间的复制,大文件传输性能提升数倍。
网络性能对比
传统 IO 服务端
text
ServerSocket server = new ServerSocket(8080);
while (true) {
Socket client = server.accept(); // 阻塞
new Thread(() -> {
try {
InputStream in = client.getInputStream();
// 每个连接一个线程
} finally {
client.close();
}
}).start();
}
问题:
- 连接数 = 线程数,资源消耗大
- 线程创建销毁开销
- 线程切换开销
- 高并发下性能急剧下降
NIO 服务端
text
Selector selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
for (SelectionKey key : selector.selectedKeys()) {
// 单线程处理多连接
}
}
优势:
- 单线程管理多连接
- 无线程创建开销
- 高并发下性能稳定
性能测试参考
| 场景 | 传统 IO | NIO | 性能差异 |
|---|---|---|---|
| 小文件复制(<1MB) | 快 | 略慢 | IO 简单场景更优 |
| 大文件复制(>100MB) | 慢 | 快(零拷贝) | NIO 显著提升 |
| 低并发网络(<100连接) | 可接受 | 复杂 | IO 足够 |
| 高并发网络(>1000连接) | 性能下降 | 稳定 | NIO 必须 |
适用场景
| 场景 | 推荐 | 原因 |
|---|---|---|
| 简单文件读写 | 传统 IO | API 简单,代码清晰 |
| 大文件复制 | NIO | 零拷贝性能优势 |
| 低并发网络 | 传统 IO | 足够,开发简单 |
| 高并发网络 | NIO | 单线程多连接,必须 |
| 实时数据流 | NIO | 非阻塞,响应及时 |
要点总结
- 传统 IO 阻塞模式,一连接一线程,低并发可用
- NIO 非阻塞模式,单线程多连接,高并发必须
- NIO 零拷贝(transferFrom)大文件性能显著提升
- 传统 IO API 简单,适合简单文件和低并发场景
- NIO 复杂但强大,适合高并发和大文件场景
- 实际开发:简单场景用 IO,高并发/大文件用 NIO
📝 发现内容有误?点击此处直接编辑