javaNIO--前述I/O模型

来源:互联网 发布:网络信息安全培训ppt 编辑:程序博客网 时间:2024/04/29 17:33

概念

在讲解NIO之前,先了解一下I/O的一些基本概念,这些概念经常会遇到,也经常会被混淆。

同步和异步

  • 同步: 当有多个任务或者事件同时发生时,这些任务或者事件比较逐个执行,一个任务或事件的执行必然导致整个流程暂时等待,这些任务无法并行执行。

  • 异步: 当有多个任务或者事件同时发生时,这些任务或者事件可以同时执行,一个事件的执行不会导致整个流程的停滞。

例如,下面这段代码就是同步

  void function(){      fun1();      fun2()      .....      .....  }

而下面这段就是异步

void function(){   new Thread(){        public void run() {            fun1();        }    }.start();    new Thread(){        public void run() {            fun2();        }    }.start();}

* 同步和异步范围比较大,指的是执行的任务或者事件 *

阻塞和非阻塞

  • 阻塞:当我们执行一个任务的中的一个请求时,这个请求需要的数据资源没有准备好,那么当前任务就会一直等待,直到数据准备好为止。

  • 非阻塞:当我们执行一个请求时,这个请求需要的条件没有满足,那么不会一直等待,而是立刻返回一个标志信息告诉说条件不满足。

所以两者的区别主要在于当条件不满足时是一直等待,还是返回不满足的标志信息。

* 阻塞和非阻塞的范围就变小了,他们指的是一个任务中具体的一个请求 *

阻塞IO和非阻塞IO

IO指的就是磁盘、硬盘、外接设备的读写,包括socket的读写等

  • 阻塞IO: 当发起一个IO请求时,内核会去检查请求数据是否就绪,如果没有就绪就会一直等待,直到数据准备就绪。

  • 非阻塞IO:当发起一个IO请求时,内核会去检查请求的数据是否就绪,如果没有就绪会立刻返回一个标志信息告诉用户没有就绪,等数据就绪后内核会将数据拷贝到用户线程,完成最终的IO操作请求。

所以完成的IO操作包括两个阶段

  • 检查数据完备性

  • 进行数据拷贝,由内核将数据拷贝到用户线程

* 阻塞IO和非阻塞IO范围进一步缩小,指的是一次阻塞或者非阻塞请求中的IO请求 *

同步IO和异步IO

  • 同步IO:当发起一个IO请求后,如果数据没有准备好,那么用户线程或者内核会轮询检查数据是否已经完备,当数据就绪后,在将数据拷贝到用户线程中继续执行。

  • 异步IO : 用户线程只发起IO请求,内核会自己完成后续的操作请求,然后发送通知告知用户线程IO操作已经完成。也就是说在异步IO中,不会对用户线程产生任何阻塞

同步IO和异步IO的关键区别反映在数据拷贝阶段是由用户线程完成还是内核完成。所以说异步IO必须要有操作系统的底层支持。

IO模型

阻塞IO模型

通常我们使用到的都是阻塞IO,即当我们发起一个IO请求时,数据没有就绪时,用户线程会处于阻塞状态交出cup的使用权,当数据就绪后内核会将数据拷贝到用户线程中,并返回结果给用户线程,用户线程才会接着执行。

非阻塞IO

当我们发起一个IO请求时,如果数据没有就绪会立刻返回一个未就绪的结果给用户,这个时候用户需要轮询发起IO请求,不断的检查返回标识的状态,当数据就绪并且接收到IO请求时,内核会将数据拷贝到用户线程池,用户线程会接着执行。

也就是说非阻塞IO需要我们不断的轮询发起请求,因此用户线程不会交出CUP的使用权

但是由于一直在轮询发起请求,一旦这个请求是一个长连接,那么cup的使用率会急速上升。

多路复用IO

多路复用IO是目前使用最多的,Java的NIO就是使用的多路复用IO模型

以socket为例,多路复用IO就是会有一个线程不断的轮询socket请求,当轮询到有socket的读写请求时,才会创建一个线程去执行请求。

因此在多路复用IO中只需要一个线程就可以管理多个socket,而且不会新创建线程,也不用维护和管理这些线程,只有请求发生的时候才会使用IO资源,大大节约了资源

它比非阻塞IO的优势就是,非阻塞IO的轮询socket的状态是由用户线程在执行的,而多路复用IO的socket状态的轮询是内核完成的,效率上非常高。

在Java的NIO中,是通过Selector.select()来检查通道是否有事件的,没有事件则会一直阻塞,因此NIO是会导致用户线程的阻塞。

多路复用IO模型是通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应。因此对于多路复用IO模型来说,一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。

信号驱动IO

在用户发起一个IO请求时,会在请求上注册一个信号函数,然后用户线程会接着执行,当内核将数据拷贝到用户线程后,会发送一个信号给用户线程,然后用户线程会执行注册的信号函数完成IO操作请求。

异步IO

当用户发起一个IO请求后,用户线程不会被阻塞,可以接着往下执行,所有IO操作都有内核去完成,当内核完成IO操作后会发送一个信号给用户线程,告诉用户IO操作已经完成后,这个时候就可以直接使用数据了。

与信号渠道IO不同的是,用户只需要发起一个IO请求,所有的操作都是由内核完成的,内核只需要发送一个完成信号就行了,而信号渠道IO在接收到信号后还需要用户线程去处理IO操作

异步IO才是最理想化的IO模型

前面四种IO模型实际上都属于同步IO,只有最后一种是真正的异步IO,因为无论是多路复用IO还是信号驱动模型,IO操作的第2个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程都会让用户线程阻塞。

原创粉丝点击