什么是BIO?NIO?AIO?各种IO了解一下(基于网络编程)

本文详细介绍了三种网络通信模型:BIO(阻塞IO)、NIO(非阻塞IO)和AIO(异步IO)的概念、原理及其区别。涵盖了从传统BIO到现代AIO的发展历程和技术特点。

关于IO的一些基本概念

  • 阻塞和非阻塞的区别:请求方请求后能否做其它事。
    - 阻塞IO:发起IO请求后,请求线程被挂起一直等待实际IO操作完成,返回数据。
    - 非阻塞IO:发起IO请求后,请求线程不会等待实际IO操作完成,立即返回一个标志信息。
    在这里插入图片描述
    • 同步和异步的区别:请求方是否需要等待结果返回。
      • 同步IO:线程请求后,等待结果返回。(图中的多次问询并不必要)
      • 异步IO:线程请求后,无需等待,接收方处理完后主动通知。

在这里插入图片描述

BIO是什么?

概念

  • BIO ,全称 Block-IO ,是一种阻塞 + 同步的通信模式。(其实就是传统的IO)
  • 是一个比较传统的通信方式,模式简单,使用方便。但并发处理能力低,通信耗时,依赖网速。

原理

  • 服务器通过一个 Acceptor 线程,负责监听客户端请求和为每个客户端创建一个新的线程进行链路处理。典型的一请求一应答模式
  • 若客户端数量增多,频繁地创建和销毁线程会给服务器打开很大的压力。后改良为用线程池的方式代替新增线程,被称为伪异步 IO 。

小结

BIO 模型中,通过 Socket 和 ServerSocket 实现套接字通道的通信。阻塞,同步,建立连接耗时。

NIO 是什么?

概念

  • NIO ,全称 New IO ,也叫 Non-Block IO ,是一种非阻塞 + 同步的通信模式。

原理

  • 客户端和服务器之间通过 Channel 通信。NIO 可以在 Channel 进行读写操作。这些 Channel 都会被注册在 Selector 多路复用器上。Selector 通过一个线程不停地轮询这些 Channel ,找出已经准备就绪的 Channel 执行 IO 操作,从而实现非阻塞。
  • 几个重要点:
    • 缓冲区 Buffer :它是 NIO 与 BIO 的一个重要区别。
      • BIO 是将数据直接写入或读取到流 Stream 对象中。
      • NIO 的数据操作都是在 Buffer 中进行的。Buffer 实际上是一个数组。Buffer 最常见的类型是ByteBuffer。
    • 通道 Channel :和流 Stream 不同,通道是双向的。NIO可以通过 Channel 进行数据的读、写和同时读写操作。
      • 通道分为两大类:一类是网络读写(SelectableChannel),一类是用于文件操作(FileChannel)。SocketChannel 和 ServerSocketChannel都是SelectableChannel 的子类。
    • 多路复用器 Selector :NIO 编程的基础。多路复用器提供选择已经就绪的任务的能力:就是 Selector 会不断地轮询注册在其上的通道(Channel),如果某个通道处于就绪状态,会被 Selector 轮询出来,然后通过 SelectionKey 可以取得就绪的Channel集合,从而进行后续的 IO 操作。

小结

NIO 模型中通过 SocketChannel 和 ServerSocketChannel 实现套接字通道的通信。非阻塞,同步,避免为每个 TCP 连接创建一个线程。

AIO 是什么?

概念

  • AIO ,全称 Asynchronous IO ,也叫 NIO2 ,是一种非阻塞 + 异步的通信模式。在 NIO 的基础上,引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。

原理

  • AIO 并没有采用 NIO 的多路复用器,而是使用异步通道的概念。其 read,write 方法的返回类型,都是 Future 对象。而 Future 模型是异步的,其核心思想是:去主函数等待时间

小结

  • AIO 模型中通过 AsynchronousSocketChannel 和 AsynchronousServerSocketChannel 实现套接字通道的通信。非阻塞,异步。

总结

BIO/NIO的区别

  • 线程模型不同
    • BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理。所以,线程开销大。可改良为用线程池的方式代替新创建线程,被称为伪异步 IO 。
    • NIO:多个连接一个线程,客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有新的 I/O 请求时,才启动一个线程进行处理。
  • BIO 是面向流( Stream )的,而 NIO 是面向缓冲区( Buffer )的。
  • BIO 的各种操作是阻塞的,而 NIO 的各种操作是非阻塞的。
  • BIO 的 Stream 是单向的,而 NIO 的 Channel 是双向的。

三者比较

三者比较

  • 需要注意的是,虽然图中说 NIO 的性能比不上AIO,但是在绝大多数我们日常业务场景,NIO 和 AIO 的性能差距实际没这么大。在 Netty5 中,基于 AIO 改造和支持,最后发现,性能并没有想象中这么强悍,所以 Netty5 被废弃,而是继续保持 Netty4 为主版本,使用 NIO 为主。
    NIO/BIO/AIO流程图
### Java IO模型:BIONIOAIO的概念及对比 #### 1. BIO(Blocking IOBIO 是传统的同步阻塞 I/O 模型。在这种模型中,客户端和服务器端的每个连接都需要一个独立的线程来处理数据的读写操作。当线程调用 `read()` 或 `write()` 方法时,如果当前没有数据可读或无法写入,线程会一直阻塞,直到操作完成[^1]。 - **优点**: - 实现简单,易于理解和使用。 - **缺点**: - 在高并发场景下,需要为每个连接创建一个线程,线程资源消耗大,可能导致系统性能下降。 - 线程在等待 I/O 操作完成期间无法执行其他任务,浪费了 CPU 资源[^4]。 ```java ServerSocket serverSocket = new ServerSocket(port); while (true) { Socket socket = serverSocket.accept(); // 阻塞等待连接 new Thread(new BioHandler(socket)).start(); } ``` #### 2. NIO(Non-blocking IONIO 是从 Java 1.4 开始引入的一种新的 I/O API。与传统的 BIO 不同,NIO 支持面向缓冲区的、基于通道的 I/O 操作,并且可以配置为非阻塞模式[^3]。通过使用 Selector(选择器),NIO 可以让单个线程管理多个 Channel(通道),从而显著提高系统的并发能力。 - **优点**: - 单个线程可以同时处理多个连接,减少了线程切换开销。 - 提供了更高效的文件和网络 I/O 操作。 - **缺点**: - 编程复杂度较高,需要手动管理缓冲区和选择器。 - 在某些情况下,非阻塞模式可能会导致 CPU 使用率升高,因为线程会频繁轮询检查是否有可读或可写的数据[^3]。 ```java Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.bind(new InetSocketAddress(port)); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { selector.select(); // 阻塞等待事件 Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> iterator = keys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); if (key.isAcceptable()) { // 处理新连接 } else if (key.isReadable()) { // 处理读事件 } iterator.remove(); } } ``` #### 3. AIO(Asynchronous IOAIO 是从 Java 7 开始引入的异步 I/O 模型。在这种模型中,I/O 操作是完全异步的,线程发起 I/O 请求后可以立即返回继续执行其他任务,当 I/O 操作完成后,系统会通知线程或回调指定的方法。 - **优点**: - 真正实现了异步非阻塞 I/O,线程无需轮询即可获得结果。 - 在高并发场景下性能优于 NIO。 - **缺点**: - 当前支持的平台有限,跨平台兼容性较差。 - 相较于 NIO,API 的灵活性较低,功能相对简单[^1]。 ```java AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(port)); serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() { @Override public void completed(AsynchronousSocketChannel result, Object attachment) { // 处理新连接 } @Override public void failed(Throwable exc, Object attachment) { // 处理错误 } }); ``` #### 对比总结 | 特性 | BIO | NIO | AIO | |---------------|--------------------------|------------------------------|-----------------------------| | 模型类型 | 同步阻塞 | 同步阻塞 | 异步非阻塞 | | 并发能力 | 较低 | 较高 | 最高 | | 编程复杂度 | 简单 | 中等 | 较高 | | 系统支持 | 所有平台 | 所有平台 | 部分平台 | | 应用场景 | 低并发场景 | 中高并发场景 | 极高并发场景 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值