一、BIO 用法(同步阻塞)
特点
- 一个连接启动一个线程
accept()、read()都会阻塞- 代码最简单
BIO 服务端
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
// BIO 服务端
public class BIOServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("BIO 服务端已启动,等待连接...");
while (true) {
// 阻塞,等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("客户端已连接:" + socket);
// 每来一个客户端,开一个线程
new Thread(() -> {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg;
// 阻塞读取数据
while ((msg = br.readLine()) != null) {
System.out.println("收到:" + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
BIO 客户端(可开多个测试)
java
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class BIOClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 9999);
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
Scanner scanner = new Scanner(System.in);
while (true) {
String msg = scanner.next();
osw.write(msg + "\n");
osw.flush();
}
}
}
二、NIO 用法(同步非阻塞)
重点:三大组件
- Selector:选择器(一个线程管理多个连接)
- ServerSocketChannel:服务端通道
- SocketChannel:客户端通道
- Buffer:缓冲区
NIO 服务端(一个线程处理所有连接)
java
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
// NIO 服务端
public class NIOServer {
public static void main(String[] args) throws IOException {
// 1. 创建选择器
Selector selector = Selector.open();
// 2. 开启服务端通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8888));
serverChannel.configureBlocking(false); // 非阻塞
// 3. 注册到选择器,监听连接事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO 服务端已启动");
while (true) {
// 阻塞等待事件
selector.select();
// 遍历事件
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isAcceptable()) {
// 有新连接
SocketChannel channel = serverChannel.accept();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 有数据可读
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
String msg = new String(buffer.array()).trim();
System.out.println("收到:" + msg);
}
}
}
}
}
三、AIO 用法(异步非阻塞)
特点
- 真正异步
- 基于回调
- 操作系统完成后通知
- Windows 支持好,Linux 一般
AIO 服务端
java
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.net.InetSocketAddress;
// AIO 服务端
public class AIOServer {
public static void main(String[] args) throws Exception {
AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(7777));
System.out.println("AIO 服务端已启动");
// 异步接受连接,回调处理
serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
@Override
public void completed(AsynchronousSocketChannel client, Object attachment) {
// 继续接收下一个连接
serverChannel.accept(null, this);
// 异步读取
ByteBuffer buffer = ByteBuffer.allocate(1024);
client.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer buffer) {
buffer.flip();
String msg = new String(buffer.array(), 0, result);
System.out.println("收到:" + msg);
}
@Override
public void failed(Throwable exc, ByteBuffer buffer) {}
});
}
@Override
public void failed(Throwable exc, Object attachment) {}
});
Thread.sleep(Integer.MAX_VALUE); // 保持服务端运行
}
}
四、三者用法核心区别(一眼看懂)
| 方式 | 阻塞 | 线程模型 | 核心API | 代码风格 |
|---|---|---|---|---|
| BIO | 阻塞 | 1连接1线程 | ServerSocket | 简单IO流 |
| NIO | 非阻塞 | 1线程管理N连接 | Selector/Channel | 通道+缓冲区+选择器 |
| AIO | 异步非阻塞 | 操作系统回调 | AsynchronousChannel | 回调函数 |
五、企业真实使用场景
- BIO:基本不用,并发太低
- NIO :Netty 框架(Dubbo、RocketMQ、SkyWalking、网关全用它)
- AIO:几乎不用,Linux 支持差
99% 高性能网络编程 = Netty(NIO)
总结
- BIO:流 + 阻塞 + 多线程
- NIO:通道 + 缓冲区 + 选择器(最常用)
- AIO:异步 + 回调