「IO 基础」- 聊聊 BOI、NIO 和 AIO

214 阅读4分钟

这是我参与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 包,提供了 ChannelSelectorBuffer 等新的抽象,可以构建 多路复用的同步非阻塞 的IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。

它支持面向缓冲的,基于通道的 I/O 操作方法。 对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

NIO 属于 同步非阻塞的 IO 模型

Java 中的 NIO 有几个比较重要的概念:

  1. Buffer(缓冲区):IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。
  2. Channel (通道):NIO 通过Channel(通道) 进行读写;通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。
  3. 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 系统上的性能并没有多少提升。