NIO、BIO、AIO

假如想象 提交于 2020-11-22 04:32:35

https://gitee.com/jly521/NioAio.git  NIO、AIO代码举例地址

  • 从进程级通信的维度讨论时, 阻塞和同步(非阻塞和异步)就是一对同义词, 且需要针对发送方接收方作区分对待。
    • 发送方阻塞/非阻塞(同步/异步)和接收方的阻塞/非阻塞(同步/异步) 是互不影响的。

#############################我的理解

同步和异步(宏观表现):

  • 异步能主动通知你,不用你不停的轮询
  • 同步的含义是,你是否需要亲自去处理数据

阻塞非阻塞(具体实现):

  • 调用不能直接返回结果,所采取的策略(等还是不等)

BIO(同步阻塞):

  • 比如发起读入操作,如果获取不到就会阻塞等待返回结果,整个程序挂起。

NIO(同步非阻塞):

  • channel、selector、buffer
  • 比如发起读入操作,调用handler
    • 如果获取不到就会返回读取不到状态(比如被锁),整个程序挂起,过一段时间轮询好了没
    • 如果获取到读入缓存,开启读取动作
  • 使用 select轮询就是同步

  • 每次从选中的通道读取数据可以设置阻塞和非阻塞策略,读入缓存

AIO,即NIO2.0(异步非阻塞):

  • 比如发起读入操作,
    • 如果读取不到,根本不会调用handler
    • 如果获取到读入缓存,调用handler处理
  • aio 接收客户端请求才去的是读入完成后回调处理函数,所以是异步

  • 创建的AsynchronousSocketChannel通道,名字不难看出是异步通道(非阻塞)

@@@@@@@@@@@@@@@@@@@@@@@@@@

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

BIO

  •  在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式
  • 需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求
  • 而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。

伪异步I/O编程

  • 采用线程池和任务队列可以实现一种叫做伪异步的I/O通信框架。

NIO

  • NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题: 
  • 将每一个客户端请求分配给一个线程来单独处理。
    • 操作系统本身也对线程的总数有一定的限制。
    • 如果客户端的请求过多,服务端程序可能会因为不堪重负而拒绝客户端的请求,甚至服务器可能会因此而瘫痪。

BIO与NIO一个比较重要的不同

  • 是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;
  • 而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。

  • NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面
    • 所以所有的连接只需要一个线程就可以搞定,
    • 当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式
  • 在NIO的处理方式中,
    • 当一个请求来的话,开启线程进行处理,可能会等待后端应用的资源(JDBC连接等),其实这个线程就被阻塞了,
    • 当并发上来的话,还是会有BIO一样的问题。

AIO

  • 与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。
  • 这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;
  • 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。 

汇总图:

先来个例子理解一下概念,以银行取款为例: 

  • 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写);
  • 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS(银行卡和密码),OS需要支持异步IO操作API);
  • 阻塞 : ATM排队取款,你只能等待(使用阻塞IO时,Java调用会一直阻塞到读写完成才返回);
  • 非阻塞 : 使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行读写,不断循环直到读写完成。

Java对BIO、NIO、AIO的支持:

  • Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,
    • 即客户端有连接请求时服务器端就需要启动一个线程进行处理,
    • 如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
  • Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,
    • 即客户端发送的连接请求都会注册到多路复用器上,
    • 多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
  • Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,
    • 客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,

BIO、NIO、AIO适用场景分析:

  • BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
  • NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
  • AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

同步和异步是针对应用程序和内核的交互而言的。 

  • 同步/异步是在时间上强调处理事情的结果/机会成本的两种处理策略;

阻塞和非阻塞是针对于进程在访问数据的时候

  • 阻塞方式下读取或者写入函数将一直等待,
  • 而非阻塞方式下,读取或者写入函数会立即返回一个状态值。

同步/异步是宏观上(进程间通讯,通常表现为网络IO的处理上),

  • 阻塞/非阻塞是微观上(进程内数据传输,通常表现为对本地IO的处理上);
  • 阻塞和非阻塞是同步/异步的表现形式

    标签
    易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
    该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!