模型阻塞方式线程模型适用场景
BIO阻塞一连接一线程连接少、简单应用
NIO非阻塞多连接一线程 (多路复用)高并发、高性能网络服务器 (主流)
AIO异步回调机制极高并发、重IO操作 (应用较少)

1. BIO、NIO、AIO 的区别?(面试必问)

这是 I/O 部分的“背诵题”,一定要分清楚同步/异步、阻塞/非阻塞。

  • BIO (Blocking I/O - 同步阻塞):

    • 机制: 传统的 “一连接一线程” 模型。

    • 缺点: 线程开销大。如果客户端连上来不说话(不发数据),服务端的线程就一直**卡在那里(阻塞)**傻等,浪费资源。

    • 场景: 连接数少且固定的架构(JDK 1.4 之前)。

    • 比喻: 餐厅里,一个服务员只服务一桌客人。客人不点菜,服务员就一直站那等着,干不了别的事。

  • NIO (Non-blocking I/O - 同步非阻塞):

    • 机制: “多连接一线程” 模型(多路复用)。

    • 核心: 引入了 Selector(选择器)。一个线程可以监控成千上万个连接,谁有数据来了,就处理谁;没数据时线程可以去干别的,不会卡死。

    • 场景: 连接数多且连接比较短(轻操作),如聊天服务器、Netty、Tomcat。

    • 比喻: 餐厅里,一个服务员兼顾整个大厅。他在各桌之间巡逻,谁招手(有请求)他就过去服务谁。

  • AIO (Asynchronous I/O - 异步非阻塞):

    • 机制: “回调” 模型。

    • 核心: 应用程序向操作系统发起 IO 请求后直接返回,操作系统搞定读写后,通知应用程序(通过回调函数)。

    • 场景: 连接数多且连接比较长(重操作)。注:目前 Linux 下 AIO 实现不够成熟,主流还是用 NIO。

    • 比喻: 客人写好菜单交给厨房,然后去逛街了。饭做好了,厨房打电话通知客人回来吃。


2. NIO 的三大核心组件是什么?

如果面试官问“NIO 是怎么实现的?”,你要答出这三个词:

  1. Channel (通道): 类似于流(Stream),但是双向的(既能读也能写)。

  2. Buffer (缓冲区): 数据存放的地方。NIO 是面向缓冲区的,数据必须先读入 Buffer 才能处理。

  3. Selector (选择器) —— 最重要:

    • 它就是那个“巡逻的服务员”。

    • IO 多路复用 的核心。它可以同时监听多个 Channel 的事件(如“连接就绪”、“读就绪”)。只有当 Channel 真正有事件发生时,Selector 才会醒来让线程去处理。


3. Java 怎么实现网络 IO 高并发?

答案:IO 多路复用 + 线程池(Reactor 模式)。

  • 核心思想: 不再让线程傻等 IO 操作。

  • 实现: 使用 Java NIO 的 Selector 机制,让一个(或少量)线程负责监听所有连接的请求。一旦有请求进来,分发给后端的线程池去处理具体的业务逻辑。


4. 为什么大家都不直接写 NIO,而是用 Netty?

面试官常问:“你手写过 NIO 吗?” 或者 “Netty 好在哪?”

  • 原生 NIO 的痛点:

    1. API 复杂: 也就是代码特别难写,需要处理各种 Buffer 的翻转、复位,容易写出 Bug。

    2. Epoll Bug: Java 原生 NIO 在 Linux 上有著名的空轮询 Bug(CPU 100%),虽然官方说修了,但还是有隐患。

  • Netty 的优势:

    1. 高性能: 也就是封装了 NIO,采用了高效的 Reactor 线程模型。

    2. 稳定: 解决了原生 NIO 的空轮询 Bug。

    3. 易用: API 简单,功能强大(自带编解码器、拆包粘包处理)。