知识模块
☕ Java 知识模块
五、Java IO/NIO
BIO vs NIO vs AIO

BIO vs NIO vs AIO

面试提问

"BIO、NIO、AIO 有什么区别?各自适用什么场景?"


核心概念

Java IO 模型经历了三代演进:

模型全称特点引入版本
BIOBlocking IO同步阻塞JDK 1.0
NIONon-blocking IO同步非阻塞JDK 1.4
AIOAsynchronous IO异步非阻塞JDK 1.7

BIO(同步阻塞 IO)

工作模式

┌─────────────────────────────────────────────┐
│                 BIO 模型                     │
├─────────────────────────────────────────────┤
│  Thread-1 ──阻塞──> read() ──等待──> 返回    │
│  Thread-2 ──阻塞──> read() ──等待──> 返回    │
│  Thread-3 ──阻塞──> read() ──等待──> 返回    │
│  ...                                        │
│  每个连接需要一个线程                          │
└─────────────────────────────────────────────┘

示例代码

// BIO 服务端
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {
    Socket socket = serverSocket.accept();  // 阻塞等待连接
    new Thread(() -> {
        try {
            InputStream is = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {  // 阻塞读取
                // 处理数据
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();
}

特点

  • 优点:模型简单,代码直观
  • 缺点
    • 一个连接需要一个线程,资源消耗大
    • 线程阻塞,CPU 利用率低
    • 无法支撑高并发

适用场景

  • 连接数少且固定
  • 服务端资源充足
  • 简单的请求响应模型

NIO(同步非阻塞 IO)

工作模式

┌─────────────────────────────────────────────┐
│                 NIO 模型                     │
├─────────────────────────────────────────────┤
│  Selector(多路复用器)                       │
│     ↓ 轮询                                   │
│  Channel-1 (可读) ──> 处理                   │
│  Channel-2 (可写) ──> 处理                   │
│  Channel-3 (无事件) ──> 跳过                  │
│  ...                                        │
│  一个线程管理多个连接                          │
└─────────────────────────────────────────────┘

三大核心组件

组件作用类比
Channel双向通道,可读可写铁轨
Buffer数据容器,读写都经过它火车车厢
Selector多路复用器,监控 Channel 事件调度员

示例代码

// NIO 服务端
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);  // 非阻塞模式
 
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);  // 注册接受连接事件
 
while (true) {
    selector.select();  // 阻塞直到有事件发生
    
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> iter = selectedKeys.iterator();
    
    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        iter.remove();
        
        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);
            client.read(buffer);
            // 处理数据
        }
    }
}

特点

  • 优点
    • 一个线程管理多个连接
    • 非阻塞,CPU 利用率高
    • 支持高并发
  • 缺点:模型复杂,编程难度高

适用场景

  • 连接数多且连接时间短
  • 高并发场景
  • Netty、Tomcat NIO 等框架

AIO(异步非阻塞 IO)

工作模式

┌─────────────────────────────────────────────┐
│                 AIO 模型                     │
├─────────────────────────────────────────────┤
│  应用程序发起 read() 请求                     │
│     ↓ 立即返回,不阻塞                        │
│  操作系统完成读取                             │
│     ↓ 回调                                   │
│  CompletionHandler 处理结果                   │
└─────────────────────────────────────────────┘

示例代码

// AIO 服务端
AsynchronousServerSocketChannel serverChannel = 
    AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(8080));
 
serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
    @Override
    public void completed(AsynchronousSocketChannel client, Void 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) {
                // 处理数据
            }
            
            @Override
            public void failed(Throwable exc, ByteBuffer buffer) {
                // 处理异常
            }
        });
    }
    
    @Override
    public void failed(Throwable exc, Void attachment) {
        // 处理异常
    }
});

特点

  • 优点
    • 真正的异步,操作系统完成 IO
    • 回调机制,编程相对简单
  • 缺点
    • Linux 支持不完善(epoll 边缘触发)
    • Windows 支持较好(IOCP)

适用场景

  • 连接数多且连接时间长
  • 需要真正异步的场景
  • Windows 平台

三种模型对比

对比项BIONIOAIO
阻塞方式同步阻塞同步非阻塞异步非阻塞
线程模型一连接一线程一线程多连接回调模型
并发能力
编程难度简单复杂中等
可靠性
吞吐量
Linux 支持好(epoll)一般

面试要点总结

问题答案要点
BIO 特点?同步阻塞,一连接一线程,简单但性能差
NIO 特点?同步非阻塞,Selector 多路复用,高性能
AIO 特点?异步非阻塞,操作系统完成 IO,回调机制
NIO 为什么高效?一个线程管理多个连接,减少线程切换开销
如何选择?低并发用 BIO,高并发用 NIO,Windows 高并发可考虑 AIO

相关题目

  1. Netty 为什么选择 NIO 而不是 AIO?
  2. Selector 是如何实现多路复用的?
  3. BIO 如何优化支持更多连接?
  4. 为什么 Linux 下 AIO 性能不如 NIO?

参考资料