NIO是什么 & BIO是什么 & AIO是什么

  • BIO : BlockIO,(同步)阻塞IO
  • NIO : New IO、Non-Block IO ,(同步)非阻塞IO
  • AIO : 异步非阻塞IO

BIO,NIO,AIO的区别

  • BIO: 发起请求–>一直阻塞–>处理完成
  • NIO: Selector主动轮询channel–>处理请求–>处理完成
  • AIO: 发起请求–>通知回调

java 中 IO 流分为几种?

  • 按照流向,分为输入流和输出流;
  • 按照操作单元,分为字节流和字符流; 
  • 按照流的角色,分为节点流和处理流。

Java I0流的40多个类都是从如下4个抽象类基类中派生出来的:

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

Java NIO

Java NIO(New I/O 或 Non-blocking I/O)‌ 是从 JDK 1.4 开始引入的一套高性能 I/O 操作 API,核心目标是解决传统阻塞式 I/O(BIO)在高并发、大数据量场景下的性能瓶颈。NIO最主要的就是实现了对异步操作的支持。

NIO主要三大核心

  • Channel(通道),
  • Buffer(缓冲区),
  • Selector(选择区)。

传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达),单个线程可以监听多个数据通道。

NIO缓冲区

NIO和传统IO(一下简称IO)之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

NIO的非阻塞

IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。

NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变得可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

核心应用场景

  • 高并发网络服务器
    NIO 通过 Selector 实现单线程管理多个连接(多路复用),避免为每个连接创建独立线程,显著降低系统资源消耗。适用于聊天服务器、实时通讯系统、在线游戏服务器等需处理成千上万并发连接的场景 ‌‌。

  • 高性能网络编程框架基础
    许多主流网络框架(如 Netty、MINA)底层基于 NIO 构建,利用其非阻塞特性和事件驱动模型实现高吞吐、低延迟的通信 ‌‌。

  • 大文件高效处理
    NIO 的 FileChannel 支持内存映射文件(MappedByteBuffer),可将文件直接映射到虚拟内存,减少数据在内核态与用户态之间的拷贝次数,大幅提升大文件读写效率 ‌‌。

  • 异步 I/O 基础(配合 NIO.2/AIO)
    虽然 NIO 本身是同步非阻塞,但为 JDK 7 引入的真正异步 I/O(AIO/NIO.2)奠定了基础,适用于需要极致 I/O 并发性能的场景 ‌‌。

与传统 BIO 的关键对比

特性 BIO(传统 I/O) NIO
数据传输方式 面向流(Stream) 面向缓冲区(Buffer)
阻塞行为 同步阻塞 支持同步非阻塞
线程模型 一线程一连接 单线程可处理多连接(多路复用)
通道方向 单向(InputStream/OutputStream) 双向(Channel)
适用场景 低并发、简单 I/O 高并发、高性能网络或文件操作

典型使用示例

  • 文件操作‌:使用 FileChannel + ByteBuffer 读写文件,支持零拷贝(transferTo())‌‌。
  • 网络服务‌:通过 ServerSocketChannel + Selector 实现事件驱动的非阻塞服务器 ‌‌。

若需处理百万级连接或追求极致性能,现代应用通常基于 Netty 等封装框架,而非直接使用原生 NIO,以降低开发复杂度。

内存映射文件

JAVA处理大文件,一般用BufferedReader,BufferedInputStream这类带缓冲的IO类,不过如果文件超大的话,更快的方式是采用MappedByteBuffer。

MappedByteBuffer是NIO引入的文件内存映射方案,读写性能极高。内存毕竟有限,如果要发送一个1G的文件不可能真的去分配1G的内存,这时就必须使用"直接"模式,即 MappedByteBuffer,文件映射。

Java NIO相比于传统IO的主要缺点:

  1. 复杂性增加‌:

    • NIO‌ 提供了更复杂的API,如 ChannelsBuffersSelectors 等,这增加了编程的复杂度。初学者可能会发现NIO的API更加难以理解和使用。
  2. 资源消耗‌:

    • NIO‌ 在某些情况下可能会比传统的IO方式消耗更多的内存和CPU资源,尤其是在处理大量短连接时。这是因为NIO需要更多的管理开销,例如缓冲区的管理和选择器的轮询。
  3. 阻塞与非阻塞的区别‌:

    • 虽然NIO支持非阻塞IO操作,但如果不正确使用,比如在非阻塞模式下错误地处理数据,或者在单线程中不恰当地使用选择器,可能会导致程序难以理解和维护。
  4. 错误处理‌:

    • NIO的错误处理机制(例如,通过检查每个缓冲区状态)比传统IO的异常抛出机制更复杂。开发者需要更多的代码来确保错误被适当地处理。
  5. 学习曲线‌:

    • 对于需要快速开发的应用程序,传统的IO由于其简单性(如使用InputStream和OutputStream)和易于理解的阻塞/非阻塞概念,可能更加适合。NIO的学习曲线较陡峭,需要更深入的理解。
  6. 性能瓶颈‌:

    • 在某些情况下,特别是在高负载或高并发环境中,如果NIO的实现不当(如不恰当的缓冲区大小或选择器配置),可能会导致性能瓶颈或资源争用。
  7. 跨平台支持‌:

    • 虽然Java NIO旨在提高跨平台性能和灵活性,但在某些特定的操作系统或环境中,其性能可能不如传统的IO实现稳定或高效。

在选择使用NIO还是传统IO时,应考虑应用的具体需求、性能要求以及开发者的熟练程度。对于简单的、低并发的应用,传统IO可能更加合适;而对于需要高性能和高并发的应用,NIO则可能更合适,但这也要求开发者有更深入的理解和更细致的优化工作。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐