一、几种IO模型介绍

1.1 同步/阻塞

1528018298764
同步和阻塞大体上描述的是同一种行为,比如方法A调用方法B。方法A一定要等到方法B执行完毕后,再返回。在方法B执行过程中,方法A依然占用时间片,阻塞等待方法B执行完成。这种IO模型又叫BIO 即Blocking IO

1.2 非阻塞

1528018439566
方法A调用方法B后,立即返回,不阻塞。但方法B可能需要执行很长时间,如果想要拿到方法B执行后的结果,需要循环d定时的去查询方法B的执行情况,这个查询过程也是非阻塞的,调用后立即返回。当查询到方法B已经执行完成,则方法A再调用获取数据的方法,去拉方法B的执行结果。
这种IO模型又叫NIO 即 Non Blocking IO

1.3 异步

1528019279681
方法A调用方法B时,像非阻塞模式一样,也是立即返回,只是在调用时,需注册一个回调方法。然后方法B可能执行很长时间,但这个过程方法A不占用任何时间片。在方法B执行完毕后,主动调用之前注册的回调方法。
这种IO模型又叫AIO 即 Asynchronous IO

二、IO模型在linux系统中的体现

1528026709878
linux对所有资源都当做文件来看待,对一个资源的持久句柄,就是文件描述符。一个应用程序,读某个资源的访问,不是直接进行的。而需要通过linux内核来完成。内核在数据就绪时,会将内核空间中的数据拷贝至应用程序所在的用户空间,最后应用程序才能对数据进行后续处理。

应用程序在发起资源访问时,最耗时的两处是,一是等待资源数据就绪,二是将数据从内核空间拷贝到用户空间。这两处会造成阻塞。linux 的io模型的不同,即体现在这两步操作上。

2.1 阻塞IO

1528027165265

2.2 非阻塞IO

1528027181117
需要多次调用recvfrom判断数据是否就绪,这些操作是非阻塞的。就绪后,再将数据从内核空间拷贝到应用进程所在的用户空间

2.3 多路复用器IO

1528027304832
比起上两种IO,多了一步select操作。select会阻塞直到数据就绪,这点跟阻塞IO类似。但不同的时,阻塞IO是对单个进程或线程阻塞。而select操作,是个多路复用器,多个进程或线程都可以通过它阻塞,并在任何资源就绪后返回。应用程序在select返回后,再通过recvfrom去将数据,从内核空间拷贝到应用程序的用户空间。select本身需要循环调用,以便随时监听后续的数据就绪事件。Java NIO的selector即是这种概念的实现

2.4 信号驱动IO

1528027599202
跟多路复用器IO类似,只是不是通过select来阻塞。而是通过signaction来注册信号响应函数来实现

2.5 异步IO

1528027846809
这个同开篇讲的异步模型类似。

三、几种IO模型在java中的体现

3.1 BIO

java中通过InputStream和OutputStream对资源访问的方式,就是阻塞式的
java并发操作时,返回的Future对象的get方法,也是阻塞的。

3.2 NIO

Java NIO中的通过buffer的方式读写,是非阻塞的。而Java NIO中selector,又属于一种多路复用器的技术。Java并发编程中Future对象的isDone方法,又可用在非阻塞编程中,进行轮巡获取任务执行状态。

3.3 AIO

典型的特点是,提交一个任务执行时,注册一个回调方法。提交任务执行的主线程不用等待任务执行结果,无需阻塞。任务执行完毕后,会自动执行回调方法。
Java中对异步模型的支持如下:

  • Java 8中引入了CompletableFuture
  • Guava中的Futures。其原理是,既然Java Future的get方法在等待任务执行结果时,会阻塞当前线程,那另起一个线程专门用来监听Future的执行结果,并执行回调,就能保证主线程非阻塞性,和回调执行的异步性。
  • akka
  • RxJava
  • spring reactor

四、参考资料

https://www.slideshare.net/liranbh/linux-io-72197884
http://timetobleed.com/io-models-how-you-move-your-data-matters/
http://www.cnblogs.com/LittleHann/p/3897910.html#top
https://wirelessr.gitbooks.io/working-life/content/io_model.html