什么是BIO,NIO和AIO?
一、BIO(Blocking IO)—— 阻塞式 IO
概念
BIO 全称Blocking IO,即传统的阻塞式输入输出模型。
在这种模式下,每个请求都由一个独立的线程来处理,线程会在 IO 操作(如 read()、accept() ) 上阻塞,直到数据准备好。
工作流程
-
服务端启动 ServerSocket。
-
调用 accept() 阻塞等待客户端连接。
-
为每个连接分配一个线程。
-
线程阻塞在 read(), 直到收到数据。
举例
ServerSocket server = new ServerSocket(8080);
while (true) {
// 阻塞等待客户端连接
Socket socket = server.accept();
// 每个连接分配一个线程
new Thread(() -> {
try {
InputStream in = socket.getInputStream();
byte[] buffer = new byte[1024];
// 阻塞等待客户端数据
int len = in.read(buffer);
System.out.println("收到消息:" + new String(buffer, 0, len));
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
特点
简单易用,编程模型直观。
缺点是 性能差:一个连接对应一个线程,线程数多时会带来上下文切换开销,容易导致资源耗尽。
应用场景
连接数较少、对性能要求不高的应用,例如早期的 Web 应用或小型工具型服务。
二、NIO(Non-blocking IO)—— 非阻塞 IO
概念
NIO 全称 New IO,也常被称为 Non-blocking IO,是 Java 1.4 引入的一种 基于事件驱动和多路复用 的 IO 模型。
核心组件:
Channel(通道):数据传输通道,替代传统的 Stream。
Buffer(缓冲区):数据存储容器。
Selector(选择器):单线程可管理多个通道。
工作流程
-
创建 ServerSocketChnnel 并设置为非阻塞模式。
-
注册到 Selector,监听事件(连接、读写)。
-
当有事件就绪时,Selector.select() 返回。
-
由单线程处理多个事件,而不是每个连接开线程。
举例
// 创建 Selector
Selector selector = Selector.open();
// 创建 ServerSocketChannel
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
// 设置非阻塞
serverChannel.configureBlocking(false);
// 注册到 Selector,监听 "接收连接" 事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// 阻塞直到有事件发生
selector.select();
// 获取已就绪的事件
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isAcceptable()) {
// 有新连接
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 有数据可读
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = client.read(buffer);
if (len > 0) {
System.out.println("收到消息:" + new String(buffer.array(), 0, len));
}
}
}
// 清理已处理的事件
keys.clear();
}
特点
单线程即可处理大量连接,提升性能。
使用 Buffer 和 Channel,比传统流(Stream)更灵活。
编程复杂度较高,需要手动管理 Selector、Channel、Buffer。
应用场景
高并发服务器,如聊天服务器、即时通讯系统、网关服务等。
Netty、Tomcat、Jetty 等框架基于 NIO 封装。
三、AIO(Asynchronous IO)—— 异步 IO
概念
AIO 全称 Asynchronous IO,在 Java 7 引入。
与 NIO 的“轮询”不同,AIO 采用 事件回调机制:
发起操作后立即返回。
当操作完成时,操作系统主动回调通知程序。
工作流程
-
服务端启动 AsynchronousServerSocketChnnel。
-
注册回调 CompletionHandler。
-
当有连接或数据时,系统触发回调执行。
举例
// 创建异步服务端
AsynchronousServerSocketChannel server =
AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080));
// 接收连接(异步回调)
server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel client, Void att) {
// 再次调用 accept 接收下一个连接
server.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 异步读取数据
client.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buf) {
buf.flip();
System.out.println("收到消息:" + new String(buf.array(), 0, result));
}
@Override
public void failed(Throwable exc, ByteBuffer buf) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void att) {
exc.printStackTrace();
}
});
特点
完全非阻塞,线程消耗更少。
IO 操作完成才触发回调,资源利用率高。
Java 对不同操作系统的支持不一致,实际应用相对少。
应用场景
超高并发、长连接场景(如消息推送、百万连接)。
在 Linux/Unix 上结合 epoll/kqueue,性能更佳。
四、对比总结
| 模型 | BIO | NIO | AIO |
|---|---|---|---|
| IO 特性 | 阻塞 | 非阻塞 | 异步非阻塞 |
| 线程模型 | 1 连接 1 线程 | 1 线程多连接 | 事件回调,无需占线程 |
| 编程难度 | 简单 | 中等 | 较高 |
| 性能 | 低 | 高 | 更高 |
| 应用场景 | 小型应用 | 高并发服务器 | 超大规模并发、推送系统 |
理解关键点
BIO:直来直去,容易理解,但线程开销大。
NIO:通过 Selector 管理连接,性能好,适合大部分高并发场景。
AIO:异步回调,理论上性能最优,但实际应用受限于底层实现。
五、总结
Java 的 BIO、NIO 和 AIO 展示了 IO 模型的发展路径:BIO 模型简单直观,但受限于“一连接一线程”的方式,性能低;NIO 通过 Selector 实现单线程管理多连接,成为高并发场景的主流选择;AIO 则依赖异步回调机制,理论上能实现最佳性能,但受制于底层操作系统的实现差异,在实际应用中推广有限。开发者应结合业务规模与并发需求,合理选择合适的 IO 模型。
更多推荐



所有评论(0)