
简单来说:
- BIO :一个线程处理一个连接,线程在等待时被卡死(阻塞)。
- NIO :一个线程处理多个连接,线程通过"轮询"来发现哪个连接准备好了,避免了傻等(非阻塞)。
- AIO :一个线程发起请求后就"撒手不管"了,等操作系统真正干完活儿了再来通知它(异步)。
技术解析
1. BIO (Blocking I/O - 同步阻塞IO)
- 模型: 一对一(一个连接对应一个线程)。
- 工作方式 :
- 服务器的
ServerSocket.accept()方法会阻塞,直到一个客户端连接进来。 - 为这个新连接创建一个新的线程。
- 这个新线程调用
Socket.read()方法,它会再次阻塞,直到客户端真正发送数据过来。
- 服务器的
- 优点: 编程模型最简单,易于理解。
- 缺点 : 并发能力极差。每增加一个连接,就需要增加一个线程。线程是非常宝贵的资源(占用内存、CPU上下文切换开销大)。如果10000个连接中,有9900个都在"等待"而不发送数据,服务器上就会有9900个空闲线程被白白浪费,这就是C10K问题的根源。
2. NIO (Non-blocking I/O - 同步非阻塞IO)
- 模型 : 多对一(多个连接可以注册到一个线程/Selector上)。
- 工作方式 :
- NIO引入了三个核心组件:Channel (通道), Buffer (缓冲区), Selector (选择器)。
- 所有客户端连接(Channels)都被设置为非阻塞 模式,并被注册到同一个Selector上。
- 服务器的一个线程 会调用
selector.select()方法。这个方法会阻塞 (但这是唯一的阻塞点),直到至少有一个Channel准备就绪(比如有新连接、有数据可读)。 select()方法返回后,线程会获得一个**"就绪"**的Channel列表。- 线程开始遍历 这个列表,并亲自 处理每一个就绪的Channel(
accept,read,write)。
- 优点 : 并发能力强。一个线程就可以管理成千上万的连接,极大地节省了系统资源。
- 缺点 :
- 编程模型复杂。
- 它仍然是同步 的。因为线程必须主动 去调用
select()来询问"谁准备好了?",并且在数据准备好后,必须由该线程自己 去执行read()和write()操作。
3. AIO (Asynchronous I/O - 异步非阻塞IO)
- 模型: 也叫NIO 2.0,是真正的"异步"IO。
- 工作方式 :
- 服务器线程发起一个异步 的
read()操作,并提供一个回调函数 (CompletionHandler)。 - 发起调用后,该线程立刻返回,可以去做其他任何事情。
- **操作系统(OS)**会代替这个线程去执行真正的I/O操作,并等待数据准备。
- 当OS完成所有 的数据读取后,它会主动调用 你之前提供的那个回调函数,在一个新的线程(或线程池)中执行回调逻辑。
- 服务器线程发起一个异步 的
- 优点 : 真正的异步。应用程序线程被彻底解放,实现了"请求-响应"的完全解耦。
- 缺点 :
- 编程模型最复杂(俗称"回调地狱")。
- 底层依赖操作系统的支持,在Linux下,AIO的实现并不完美(常用epoll模拟),因此在Java网络编程领域,NIO (Netty) 依然是事实上的主流。
故事场景 :一个超级繁忙的餐厅
技术是原理,现在,让我们走进一家繁忙的餐厅,看看三种不同的"服务员工作模式"。
- 你: 餐厅老板。
- 顾客: 客户端连接。
- 服务员: 服务器线程。
- 上菜: I/O操作。
模式一:BIO --- "一个服务员盯一个客人"
- 工作模式 :
- 来一位顾客,你就必须雇一个新服务员 (
new Thread)。 - 这位服务员的工作就是死死地盯住这位顾客。
- 顾客在看菜单,没点菜(客户端未发送数据),服务员就站在旁边干等 (
read()阻塞)。 - 顾客点完菜,服务员再去上菜。
- 来一位顾客,你就必须雇一个新服务员 (
- 餐厅状况 :
餐厅里坐了100桌客人,其中90桌都在聊天。但你依然要雇100个服务员,其中90个都靠在墙边发呆,白白浪费工资。
模式二:NIO --- "一个大堂经理盯全场"
- 工作模式 :
- 你只雇了一个超级厉害的大堂经理(一个线程)。
- 你给每桌客人都发了一个"服务铃 "(
Channel注册到Selector)。 - 大堂经理不盯任何一桌客人,他只盯吧台上的"总控显示屏 "(
selector.select())。 - 当第5桌的客人按下服务铃(Channel就绪),显示屏"叮"的一声亮了。
- 大堂经理被唤醒,他亲自 跑到第5桌去服务(同步处理I/O)。服务完毕后,他再跑回吧台,继续盯显示屏。
- 餐厅状况 :
一个大堂经理,就管理了全场100桌客人。没有一个员工在发呆,效率极高。但大堂经理必须自己跑来跑去,亲自服务。
模式三:AIO --- "智能点餐与机器人送餐"
- 工作模式 :
- 你雇了一个经理(一个线程),并发给每桌一个"智能点餐平板"(发起异步请求)。
- 顾客在平板上点完单,经理在后台点击"确认" (发起
read),并告诉系统:"菜做好后,让送餐机器人(OS)自己送过去,并在送达后通知我。 "(CompletionHandler回调)。 - 经理点击"确认"后,就立刻去做别的事了(比如核算账目)。
- 后厨(OS)自己做菜、自己派机器人送餐。当菜品真正送达顾客手中后,经理的电脑"叮"的一声,收到了"第5桌已送达"的通知。
- 餐厅状况 :
经理完全从"跑腿"中解放了出来,他只负责"发起"和"接收结果",所有的"执行过程"都外包给了操作系统。
故事总结:
| I/O模型 | 核心比喻 (餐厅模式) | 线程在干嘛? |
|---|---|---|
| BIO | 一个服务员盯一桌 | 阻塞 (死等顾客点菜) |
| NIO | 一个经理盯全场呼叫铃 | 同步非阻塞 (等呼叫铃响,然后自己去服务) |
| AIO | 经理下单,机器人送餐 | 异步非阻塞 (下单后就走人,等机器人来通知) |
结论:
- BIO 因其简单,仍用于一些连接数少、交互简单的场景。
- NIO 是Java并发网络编程的事实标准,所有的高性能框架(如Netty, Vert.x)都基于NIO构建。
- AIO 理念先进,但在Java生态中的应用远不如NIO广泛。