这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战
1. 前言
关于 Java 中的 IO 模型呢,陆陆续续也看了很多资料,但是每次看的都不成体系,后来在复盘的时候,发现 IO 知识在脑子里连不成一片,所以就整了这么一出
2. Java 中三种常见的 IO 模型
IO 其实就是 Input/Output,输入和输出。
在计算机硬件的角度来看,CPU 的速度是极快的;那一些非常慢的输入设备,比如键盘;你搁这打字,一分钟打一万字,你以为你起飞了666,但人家CPU觉得你真男人,真持久;假如 CPU 这段时间啥也不干,就硬等,这样对程序的运行效率产生了极大的影响,为了解决这个问题,就有了不同的 IO 模型
2.1 BIO (Blocking IO)
顾名思义,Blocking IO,这是会导致阻塞的 IO 模型;BIO 其实就是传统的 java.io 包,它是基于流模型实现的,交互的方式是同步、阻塞方式。
怎么理解这个,比如 Java 程序等待一个用户输入指令,在接收到用户指令之前,整个 Java 程序是阻塞的状态,其他任何操作都无法完成。
也就是说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,在客户端连接数量不高的情况下,是没问题的。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
BIO 属于同步阻塞模型

2.2 NIO(Non-Blocking IO 或 New IO)
为了解决 BIO 的性能瓶颈,Java 1.4 引入了 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建 多路复用的、同步非阻塞 的IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。
它支持面向缓冲的,基于通道的 I/O 操作方法。 对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
NIO 属于 同步非阻塞的 IO 模型

Java 中的 NIO 有几个比较重要的概念:
- Buffer(缓冲区):IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。
- Channel (通道):NIO 通过Channel(通道) 进行读写;通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。
- Selectors(选择器):选择器用于使用单个线程处理多个通道。通过它,只需要一个线程便可以管理多个客户端连接。当客户端数据到了之后,才会为其服务

2.3 AIO
AIO 也就是 NIO 2,Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型
异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。

3. 应当如何选择
- BIO 适用于连接数目比较小且固定的结构。它对服务器资源要求比较高,并发局限于应用中,JDK1.4之前唯一选择,但程序直观简单易理解
- NIO 适用于连接数目多且连接比较短的架构,比如聊天服务器,并发局限于应用中,变成比较复杂。JDK1.4开始支持,比如 Nginx 和 Netty 就是基于 NIO 来实现的
- AIO 适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用 OS 参与并发操作,编程比较复杂,JDK7 开始支持,在成长中,Netty 曾经使用过,后来放弃,原因是使用了 AIO 之后,在 Linux 系统上的性能并没有多少提升。