BIO、NIO、AIO 的区别分析


BIO、NIO、AIO 的区别

在讲 BIO,NIO,AIO 之前先来回顾一下这样几个概念:同步与异步,阻塞与非阻塞。

同步

自己的理解:

也就是必须一件一件事做,等前一件做完了才能做下一件事 (提交请求->等待服务器处理->处理完返回 这个期间客户端浏览器不能干任何事 )
官方:
使用同步 IO 时,Java 自己处理 IO 读写。

异步

自己的理解:

请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
官方:
使用异步 IO 时,Java 将 IO 读写委托给 OS 处理,需要将数据缓冲区地址和大小传给 OS,完成后 OS 通知 Java 处理(回调)。

阻塞

自己的理解:

阻塞就是说在煮水的过程中,你不可以去干其他的事情(性能和可靠性都不好)
官方:
使用阻塞 IO 时,Java 调用会一直阻塞到读写完成才返回。

非阻塞

自己的理解:

非阻塞就是在同样的情况下,可以同时去干其他的事情(对于低负载、低并发的应用程序)
官方:
使用非阻塞 IO 时,如果不能立马读写,Java 调用会马上返回,当 IO 事件分发器通知可读写时在进行读写,不断循环直到读写完成。

IO 的方式通常分为几种,同步阻塞的 BIO、同步非阻塞的 NIO、异步非阻塞的 AIO。

传统的 BIO(同步阻塞的 BIO)

就是说服务端一旦接受客户端的连接,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成,不过可以通过多线程来支持多个客户端的连接,循环导致高 cpu 消耗。
服务器的实现模式是一个连接一个线程,这样的模式很明显的一个缺陷是:
由于客户端连接数与服务器线程数成正比关系,可能造成不必要的线程开销,严重的还将导致服务器内存溢出。当然,这种情况可以通过线程池机制改善,但并不能从本质上消除这个弊端。
问题:当出现高并发怎么办?
解决这个问题就有了下面的。

NIO(同步非阻塞的 NIO)。它支持面向缓冲的,基于通道的 I/O 操作方法

从 JDK1.4 以后开始,JDK 引入的新的 IO 模型 NIO。

  • Channel(通道):通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和 Buffer 交互。因为 Buffer,通道可以异步地读写。
  • Buffer(缓冲区):Buffer 是一个对象,它包含一些要写入或者要读出的数据。
  • Selector(选择器):选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。线程之间的切换对于操作系统来说是昂贵的。因此,为了提高系统效率选择器是有用的。

就是说加了三个功能来解决 bio 中的单线程一对多的问题。

而服务器的实现模式是多个请求一个线程,即请求会注册到多路复用器 Selector 上,多路复用器轮询到连接有 IO 请求时才启动一个线程处理。

Java NIO: 单线程管理多个连接。

劣处:维护成本高,容易出现 bug,项目大了之后消耗成本。

AIO(异步非阻塞的 AIO)

JDK1.7 发布了 NIO2.0 也可以说是 NIO 的加强版,它是异步非阻塞的 IO 模型。

异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。

这就是真正意义上的异步非阻塞,服务器的实现模式为多个有效请求一个线程,客户端的 IO 请求都是由 OS 先完成再通知服务器应用去启动线程处理(回调)。

应用场景:并发连接数不多时采用 BIO,因为它编程和调试都非常简单,但如果涉及到高并发的情况,应选择 NIO 或 AIO,更好的建议是采用成熟的网络通信框架 Netty。

总结

理解了这,浓缩了还是有点东西的。

  • BIO 是一个连接一个线程。
  • NIO 是一个请求一个线程。
  • AIO 是一个有效请求一个线程。

文章作者: 程序猿洞晓
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 程序猿洞晓 !
评论
 上一篇
Vue3知识学习笔录 Vue3知识学习笔录
不会前端开发的后端研发人员不是个好爸爸,所以当了爸爸的我要多学习,给未来的程序猿小朋友做个榜样。
2023-03-03
下一篇 
Centos 7、windows环境下在线和离线安装PostgreSQL Centos 7、windows环境下在线和离线安装PostgreSQL
PostgreSQL在线安装和离线安装的区别,主要涉及的是依赖的安装,其他安装步骤离线和在线基本相同,刚好当前的这个项目需要使用到此数据库,需要搭建数据库环境,特此记录。
2022-11-01
  目录