Java中提供的IO有关的API,在文件处理的时候,其实依赖操作系统层面的IO操作实现的(关于Java对IO的三种封装,可见我的另一篇博客)
开门见山,Linux下的如中IO模型:阻塞IO模型,非阻塞IO模型,IO复用模型,信号驱动IO模型,异步IO模型,见下图
接下来一一讲解这5种模型
阻塞型IO:最简单的一种IO模型,简单理解就是死等,即进程或线程一直等待莫格条件,不满足则一直等待。
非阻塞型IO:应用进程与内核交互,目的未达到之前会直接返回,然后不断轮询,不停的去问内核数据是否准备好?如果发现准备好了,那就把数据拷贝到用户空间中。应用进程通过 recvfrom 调用不停的去和内核交互,直到内核准备好数据。如果没有准备好,内
核会返回error,应用进程在得到error后,过一段时间再发送recvfrom请求。在两次发送请求的时间段,进程可以先做别的事情。
信号驱动IO:我们会发现非阻塞型IO方式一遍一遍的轮询不如等内核把数据准备好,然后通知进程,当进程收到该通知时,便开始把数据拷贝到用户空间中。 即应用进程预先向内核注册一个信号处理函数,然后用户进程返回,并不阻塞,当内核数据准备就绪时会发送一个信号给进程,用户进程便在信号处理函数中开始把数据拷贝到用户空间中
IO复用模型:顾名思义,即将多个进程I/0注册到同一管道上,这里管道会统一和内核交互。当管道中的某一个请求需要好的数据准备好之后,进程再把对应的数据拷贝到用户空间中。 I/O多路转接是多了一个Select函数,多个进程的IO可以注册到同一个Select中,用户调用该Select。Select会监听所有注册好的I/O,如果所有被监听的I/O需要的数据都没有准备好,Select调用进程会阻塞。当任意一个I/O所需要的数据准备好之后,Select调用就
会返回,然后进程再通过recvfrom来进行数据拷贝。但实际上,它并未向内核注册信号处理函数,所以它并不是非阻塞的。
看到开篇的那张图,大家肯定会有疑问,为什么之前的这四种模型都是同步的呢?因为无论以上哪种模型,真正的数据拷贝过程都是同步的(自己的理解便是:所有的数据拷贝过程都是用户进程手动执行的)
那么我们来看真正异步执行的I/O模型:
异步I/O模型:应用进程把I/O请求传给内核后,完全由内核去操作文件拷贝。内核完成相关操作后,会发信号告诉应用进程本次I/O已经完成。用户进程发起aio_read操作之后,给内核传递描述符、缓冲区指针、缓冲区大小等,告诉内核进程当整个操作完成时,如何通知进程,然后就立刻去做其他事儿了。当内核收到aio_read后,会立刻返回,然后内核开始等待数据准备,数据准备好以后,直接把数据拷贝到用户控件,然后再通知进程本次IO已经完成。
各个模型的执行流程比较图如下图所示