你真的理解BIO、NIO、AIO的区别吗?

点击上方 "编程技术圈"关注, 星标或置顶一起成长

后台回复“大礼包”有惊喜礼包!

日英文

Tired heart is always hovering between adhering to and giving up, indecisive. Trouble is that memory is good, the mind should not mind will stay in memory.

心累,就是常常徘徊在坚持和放弃之间,举棋不定。烦恼,就是记性太好,该记的,不该记的都会留在记忆里。

每日掏心话

看着一路走来时的脚步,有苦,有甜,有笑,有泪。在走走停停之后,放慢了匆忙的脚步,感受那一路走来的弥足珍贵。
责编:乐乐 | 来自:juejin.cn/post/6844903985158045703

编程技术圈(ID:study_tech)第 1244 次推文

往日回顾:华为败诉,“鸿蒙”商标申请被驳回

     

   正文   



很多文章在谈论到BIO、NIO、AIO的时候仅仅是抛出一堆定义,以及一些生动的例子。看似很好理解。但是并没有将最基础的本质原理显现出来,如果没有没有从IO的原理出发的话是很难理解这三者之间的区别的。所以本篇文章从Java是如何进行IO操作为开头进行分析。
Java中的IO原理首先Java中的IO都是依赖操作系统内核进行的,我们程序中的IO读写其实调用的是操作系统内核中的read&write两大系统调用。
那内核是如何进行IO交互的呢?
网卡收到经过网线传来的网络数据,并将网络数据写到内存中。
当网卡把数据写入到内存后,网卡向cpu发出一个中断信号,操作系统便能得知有新数据到来,再通过网卡中断程序去处理数据。
将内存中的网络数据写入到对应socket的接收缓冲区中。
当接收缓冲区的数据写好之后,应用程序开始进行数据处理。
对应抽象到java的socket代码简单示例如下:
public class SocketServer {
  public static void main(String[] args) throws Exception {
    // 监听指定的端口
    int port = 8080;
    ServerSocket server = new ServerSocket(port);
    // server将一直等待连接的到来
    Socket socket = server.accept();
    // 建立好连接后,从socket中获取输入流,并建立缓冲区进行读取
    InputStream inputStream = socket.getInputStream();
    byte[] bytes = new byte[1024];
    int len;
    while ((len = inputStream.read(bytes)) != -1) {
      //获取数据进行处理
      String message = new String(bytes, 0, len,"UTF-8");
    }
    // socket、server,流关闭操作,省略不表
  }
}
可以看到这个过程和底层内核的网络IO很类似,主要体现在accept()等待从网络中的请求到来然后bytes[]数组作为缓冲区等待数据填满后进行处理。而BIO、NIO、AIO之间的区别就在于这些操作是同步还是异步,阻塞还是非阻塞。
所以我们引出同步异步,阻塞与非阻塞的概念。
同步与异步同步和异步指的是一个执行流程中每个方法是否必须依赖前一个方法完成后才可以继续执行。假设我们的执行流程中:依次是方法一和方法二。
同步指的是调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。即方法二一定要等到方法一执行完成后才可以执行。
异步指的是调用立刻返回,调用者不必等待方法内的代码执行结束,就可以继续后续的行为。(具体方法内的代码交由另外的线程执行完成后,可能会进行回调)。即执行方法一的时候,直接交给其他线程执行,不由主线程执行,也就不会阻塞主线程,所以方法二不必等到方法一完成即可开始执行。
同步与异步关注的是方法的执行方是主线程还是其他线程,主线程的话需要等待方法执行完成,其他线程的话无需等待立刻返回方法调用,主线程可以直接执行接下来的代码。
同步与异步是从多个线程之间的协调来实现效率差异。
为什么需要异步呢?笔者认为异步的本质就是为了解决主线程的阻塞,所以网上很多讨论把同步异步、阻塞非阻塞进行了四种组合,其中一种就有异步阻塞这一情形,如果异步也是阻塞的?那为什么要特地进行异步操作呢?
阻塞与非阻塞阻塞与非阻塞指的是单个线程内遇到同步等待时,是否在原地不做任何操作。
阻塞指的是遇到同步等待后,一直在原地等待同步方法处理完成。
非阻塞指的是遇到同步等待,不在原地等待,先去做其他的操作,隔断时间再来观察同步方法是否完成。
搜索公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。
阻塞与非阻塞关注的是线程是否在原地等待。
笔者认为阻塞和非阻塞仅能与同步进行组合。而异步天然就是非阻塞的,而这个非阻塞是对主线程而言。(可能有人认为异步方法里面放入阻塞操作的话就是异步阻塞,但是思考一下,正是因为是阻塞操作所以才会将它放入异步方法中,不要阻塞主线程)
例子讲解海底捞很好吃,但是经常要排队。我们就以生活中的这个例子进行讲解。
A顾客去吃海底捞,就这样干坐着等了一小时,然后才开始吃火锅。(BIO)
B顾客去吃海底捞,他一看要等挺久,于是去逛商场,每次逛一会就跑回来看有没有排到他。于是他最后既购了物,又吃上海底捞了。(NIO)
C顾客去吃海底捞,由于他是高级会员,所以店长说,你去商场随便玩吧,等下有位置,我立马打电话给你。于是C顾客不用干坐着等,也不用每过一会儿就跑回来看有没有等到,最后也吃上了海底捞(AIO)
哪种方式更有效率呢?是不是一目了然呢?
BIOBIO全称是Blocking IO,是JDK1.4之前的传统IO模型,本身是同步阻塞模式。线程发起IO请求后,一直阻塞IO,直到缓冲区数据就绪后,再进入下一步操作。针对网络通信都是一请求一应答的方式,虽然简化了上层的应用开发,但在性能和可靠性方面存在着巨大瓶颈,试想一下如果每个请求都需要新建一个线程来专门处理,那么在高并发的场景下,机器资源很快就会被耗尽。
NIONIO也叫Non-Blocking IO 是同步非阻塞的IO模型。线程发起io请求后,立即返回(非阻塞io)。同步指的是必须等待IO缓冲区内的数据就绪,而非阻塞指的是,用户线程不原地等待IO缓冲区,可以先做一些其他操作,但是要定时轮询检查IO缓冲区数据是否就绪。
Java中的NIO 是new IO的意思。其实是NIO加上IO多路复用技术。普通的NIO是线程轮询查看一个IO缓冲区是否就绪,而Java中的new IO指的是线程轮询地去查看一堆IO缓冲区中哪些就绪,这是一种IO多路复用的思想。IO多路复用模型中,将检查IO数据是否就绪的任务,交给系统级别的select或epoll模型,由系统进行监控,减轻用户线程负担。
NIO主要有buffer、channel、selector三种技术的整合,通过零拷贝的buffer取得数据,每一个客户端通过channel在selector(多路复用器)上进行注册。服务端不断轮询channel来获取客户端的信息。channel上有connect,accept(阻塞)、read(可读)、write(可写)四种状态标识。根据标识来进行后续操作。所以一个服务端可接收无限多的channel。不需要新开一个线程。大大提升了性能。
AIOAIO是真正意义上的异步非阻塞IO模型。上述NIO实现中,需要用户线程定时轮询,去检查IO缓冲区数据是否就绪,占用应用程序线程资源,其实轮询相当于还是阻塞的,并非真正解放当前线程,因为它还是需要去查询哪些IO就绪。而真正的理想的异步非阻塞IO应该让内核系统完成,用户线程只需要告诉内核,当缓冲区就绪后,通知我或者执行我交给你的回调函数。
AIO可以做到真正的异步的操作,但实现起来比较复杂,支持纯异步IO的操作系统非常少,目前也就windows是IOCP技术实现了,而在Linux上,底层还是是使用的epoll实现的。
笔者个人理解总结,如有错误恳请网友评论指正。
PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。


版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

欢迎加入后端架构师交流群,在后台回复“学习”即可。

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。在这里,我为大家准备了一份2021年最新最全BAT等大厂Java面试经验总结。
别找了,想获取史上最简单的Java大厂面试题学习资料
扫下方二维码回复「面试」就好了


猜你还想看
阿里、腾讯、百度、华为、京东最新面试题汇集
后端接口如何提高性能?

鸿蒙OS 2.0今起开源:是否套壳Android 460万行代码里见

还在写大量 if 来判断?试试用一个规则执行器来替代它

嘿,你在看吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值