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

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

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

日英文数据库

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.编程

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

每日掏心话后端

看着一路走来时的脚步,有苦,有甜,有笑,有泪。在走走停停以后,放慢了匆忙的脚步,感觉那一路走来的弥足珍贵。数组

责编:乐乐 | 来自: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 来判断?试试用一个规则执行器来替代它

嘿,你在看吗?
相关文章
相关标签/搜索