Java面试题:BIO、AIO、NIO的区别(BIO、AIO、NIO知识点剖析和演示面试)

面试官提了这样一个问题:

请说说BIO、AIO、NIO的区别?

知识点剖析

IO是什么

用中国话说,IO = 输入/输出

英文全写,IO = in/out

从表现上来看,IO = 读写文件,微信发消息,网上看电影,键盘信号,信息显示在显示器上,这些都是基于输入输出的。

从技术核心来说,IO = 一个个的字节从一个地方进入内存,或者从内存传到另一个地方。

IO的中心是内存,是针对内存的方向说的in(入),针对内存的方向说的out(出)

IO基本来说做计算机的人都能理解这个是啥东西,哪里会用到这个。但做软件开发的就需要从原理、模型、性能方面来理解,具体到最后还得会写程序,这个就比较复杂了。我这里不说怎么写程序,只说模型和原理,希望帮助你理解IO和三代IO是怎么回事,原理理解了,到具体写代码的时候就很简单了。

* BIO的模型和原理

BIO的英文全称是Block IO,就是阻塞式IO

这是最原始的模型,这个模型的特点就是同步+阻塞,结果就是高并发下性能很差。

举个聊天服务器的例子:

聊天服务器端,有一个线程充当看门老头儿的角色,等着有新用户创建聊天连接请求,他啥也不干,就等着有新用户来了做接待工作。

新用户来了,这个门房老头线程把这个请求连接创建好,然后交个另一个处理聊天业务的线程为新用户服务,这时候门房老头继续等着新用户上门。

接下来说负责这个用户服务的线程,只能负责一个连接请求。也就是有一个用户要聊天就有一个业务线程创建出来了。如果有100个用户进来了,就得创建100个业务线程。

这种模型下,有一个只负责接待的线程,就是那个门房老头,他是阻塞的,也是同步的。

每个处理聊天业务的线程也是阻塞的,也是同步的。

* BIO的优点

这种模型的结构简单,一看就明白,也好理解。

* BIO存在的问题

问题是一旦聊天的用户多了,线程就会蹭蹭的增加,线程的效率太低了,这个模型结构处理高并发的业务就会出问题。

* NIO的模型和原理

在JDK1.5就推出了一个新的IO叫NIO,有人称其为New IO,我更愿意称其为NonBlock IO。

目的就是解决BIO的高并发性能问题。

如何实现的呢?这个就要从设计模式来解释了。NIO采用了Reactor的设计模式,这个Reactor中最牛的地方是提供了一个Selector和一个Dispacher,Selector是负责监听流事件的,Dispatcher负责将事件消息内容分发给具体的方法来处理。这俩兄弟配合到一起,扮演了收发室老头的工作。收发室老头儿负责接收信件(Selector),并把信件送到各科室(Dispatcher)。

这种模式下带来的最大的改善,不需要每个通信连接由一个单独的线程来处理了,在消息内容分发后,调用的业务处理程序可以都在一个线程中执行,然后减少了线程创建和线程切换的花销,从而大大提升了程序性能。

那么我们可能把BIO改造一下,也实现高并发不?其实也不是不可能,比如Http请求,每次请求有大量的连接,一个图片是一个连接、一个css也是一个连接,一个js文件也是一个连接,说明一下,我们不考虑http2.0对连接复用的机制,只基于简化的http模型来说明这个问题。但其实我们可以发现,http的每次请求在服务端处理的时间都很短,这样我们可以采用线程池的概念,启动若干个线程放到线程池,每个http请求都是一个任务,创建一个任务然后看看线程池里面有没有闲的线程,如果有的话就直接复用闲置的线程,没有空闲线程的话可以把任务放入队列,也可以创建新线程,这些是线程池的不同策略。从而实现线程的复用。因为BIO核心的问题并不是单任务性能差,而是高并发会出现线程创建和线程切换的花销。

当然,依旧是NIO更牛,因为NIO是从操作系统层实现的,我们自己写优化的话,一定不如NIO的性能好。

* NIO存在的问题

NIO这么牛了,是不是就是终极解决方案了?其实也不是。NIO也存在问题,因为NIO的方式是在一个线程中处理多个业务请求,从而降低多线程创建和切换造成的时间和资源的消耗,但我们知道线程中的程序只能有一个执行,不可能两个方法都执行,别说俩方法了,两行代码也得一行执行完了另一行执行。那么如果NIO的一个消息处理时间比较长,就会造成麻烦了,其他的消息都干不了活了。

NIO模型存在这个问题,是不是一听感觉麻烦大了?其实也不是,因为NIO适合的场景是每个消息处理时间都不长的情景,这种情景下性能极高。曾经有过在windows下写的电信行业的业务处理模块,每秒30万条的消息,几百兆大小,跑起来CPU也就 20%左右的使用率。

所以NIO是没办法处理每个消息的处理时间太长的业务。这可怎么办呢?多线程解决嘛,也可以将NIO的业务处理放到多个任务里面,然后放到线程池来处理,这样一个线程处理时间长,不会影响另一个线程。如此一来,世界美丽,回头看看,似乎跟BIO的优化方案差不多,这多线程池似乎是一切高并发IO问题的终极解决办法啊。

这就引出了AIO。

* AIO的模型和原理

AIO的模型核心就是在NIO的基础上增加了一个线程池,每个消息的处理交给一个线程来处理,这个线程池谁维护的?操作系统维护的,那是计算机里面的终极大BOSS,一定比我们自己写的线程池方案要优秀的多。

当然AIO不仅仅是这些优化,在数据流接收和分发机制方面都做了优化,不过,这些都不是核心最优秀的特性,我们这里不做过多评估。

AIO的设计模型是基于Proactor,这个又涉及到设计模式,这个设计模式是啥意思呢?Proactor模式的思想是有消息了,消息通道帮我接收好,全部收好后通知我,我取了消息后通知业务代码来处理消息。这里我们看看,Proactor在中间需要处理的工作很轻量,收消息他不操心,消息都收好了他才得到通知去取消息,他取了消息后并不做复杂的处理,只是通知业务代码去处理消息,在这个过程中,Proactor处理的工作量很轻。事实上,从代码层分析AIO也比BIO和NIO简单。Proactor像是一个甩手掌柜,负责指挥干活,但自己啥事儿不干。

因此总结一下就是AIO一切都是非阻塞的事件来驱动的,然后所有的业务处理都是异步的,因为业务都是在线程池中执行的。并且,所有这些都是在操作系统级别处理的,性能及其优秀。

* 三者的使用场景的比较

BIO适合处理低并发的IO通信。

NIO适合处理高并发,但每个并发执行时间很短的IO通信。

AIO适合处理高并发,且每个并发执行时间都较长的IO通信。

BIO是同步阻塞的

NIO是同步非阻塞的

AIO是异步非阻塞的

演示面试

基本概念说完了,我就开始做演示面试:

你好,面试官。

BIO全称是Block IO,是同步阻塞的,这个模型结构最简单,最容易理解。

NIO是NonBlock IO,是同步非阻塞的,NIO的模型是Reactor的。

AIO是异步非阻塞的,AIO的模型是Proactor的。

NIO中引入了通道、缓冲区和Selector,通道对应BIO的流,缓冲区对应BIO中的自定义byte数组,Selector作为事件选择器,将消息分发给不同的处理代码去处理。

NIO可以将多连接的任务放在一个线程下完成。

AIO中继续使用NIO的通道、缓冲区的概念,在消息分发的方式上采用了事件和回调的方式实现,从而达到极其高效的消息响应效率,和极低的资源消耗。

AIO基于线程池的思路实现了任务的异步,这些都是基于操作系统实现的。

NIO和AIO在底层都是基于操作系统的select/poll/epoll,在windows下基于ICOP,性能非常优秀。

=========================================================

以上就是我的演示面试,不知道是否让你满意。

给TA打赏
共{{data.count}}人
人已打赏
Java

Java面试题:File类有哪些常用方法(File类知识点剖析和演示面试)

2023-2-21 10:39:27

Java

Java面试题:Java的IO流有哪几种(IO流知识点剖析和演示面试)

2023-2-21 13:15:20

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索
打开微信,扫描左侧二维码,关注【旅游人lvyouren】,发送【101】获取验证码,输入获取到的验证码即可解锁复制功能,解锁之后可复制网站任意一篇文章,验证码每月更新一次。
提交