1. BIO (Blocking I/O) - 同步阻塞 I/O
BIO 是传统的网络编程模型,每个连接对应一个线程,当线程执行读/写操作时会被阻塞,直到数据就绪。
示例:BIO 服务器
java
import java.net.*;
import java.io.*;
public class BioServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("BIO Server started on port 8080");
while (true) {
Socket clientSocket = serverSocket.accept(); // 阻塞等待客户端连接
new Thread(() -> {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String request;
while ((request = in.readLine()) != null) { // 阻塞读取数据
System.out.println("Received: " + request);
out.println("Echo: " + request); // 响应客户端
}
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
特点:
- 每个连接一个线程,适合连接数少的场景。
- 编程简单,但线程开销大,无法应对高并发。
2. NIO (Non-blocking I/O) - 同步非阻塞 I/O
NIO 基于 Channel 和 Selector,使用单个线程管理多个连接,通过事件驱动机制实现非阻塞。
示例:NIO 服务器
java
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;
public class NioServer {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false); // 非阻塞模式
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 注册接受连接事件
System.out.println("NIO Server started on port 8080");
while (true) {
selector.select(); // 阻塞直到有事件发生
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
iter.remove();
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ); // 注册读事件
System.out.println("Client connected: " + client.getRemoteAddress());
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = client.read(buffer); // 非阻塞读取
if (read > 0) {
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
String request = new String(data);
System.out.println("Received: " + request);
// 响应客户端
ByteBuffer response = ByteBuffer.wrap(("Echo: " + request).getBytes());
client.write(response);
} else if (read == -1) {
client.close();
}
}
}
}
}
}
特点:
- 单线程处理多连接,减少线程开销。
- 复杂度较高,需要处理事件循环和缓冲区。
3. AIO (Asynchronous I/O) - 异步非阻塞 I/O
AIO 基于回调机制,应用程序发起 I/O 操作后立即返回,当操作完成时系统会通知应用程序。
示例:AIO 服务器
java
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.concurrent.*;
public class AioServer {
public static void main(String[] args) throws IOException {
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();
server.bind(new InetSocketAddress(8080));
System.out.println("AIO Server started on port 8080");
// 接受连接的回调
server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(AsynchronousSocketChannel client, Void attachment) {
server.accept(null, this); // 继续接受下一个连接
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 读取数据的回调
client.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer bytesRead, ByteBuffer buffer) {
if (bytesRead > 0) {
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
String request = new String(data);
System.out.println("Received: " + request);
// 响应客户端
ByteBuffer response = ByteBuffer.wrap(("Echo: " + request).getBytes());
client.write(response, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
exc.printStackTrace();
}
});
// 保持服务器运行
Thread.currentThread().join();
}
}
特点:
- 完全异步,基于回调或 Future,性能高。
- 编程模型复杂,适合连接数多且长连接的场景。
对比分析
| 特性 | BIO | NIO | AIO |
|---|---|---|---|
| 模型 | 同步阻塞 | 同步非阻塞(多路复用) | 异步非阻塞 |
| 线程数 | 一个连接一个线程 | 一个线程处理多个连接 | 少量线程,回调驱动 |
| 吞吐量 | 低(线程上下文切换开销大) | 中高 | 高 |
| 编程复杂度 | 简单 | 复杂(需处理 Selector 等) | 非常复杂(回调地狱) |
| 适用场景 | 连接数少、固定架构 | 连接数多、短连接(如聊天) | 连接数多、长连接(如文件传输) |
| JDK 版本 | Java 1.0+ | Java 1.4+ | Java 1.7+ |
总结
- BIO:简单但性能差,适合低并发场景。
- NIO:性能较好,复杂度高,适合高并发短连接(Netty 基于 NIO)。
- AIO:性能最佳,但编程复杂,在 Linux 上优势不明显(Linux 对 AIO 支持有限,常用 NIO)。
实际项目中,NIO 框架(如 Netty)使用最广泛,平衡了性能和复杂度。