4.信号驱动IO模型
  在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的IO请求操作。
  5.异步IO模型
  异步IO模型才是理想的IO模型,在异步IO模型中,当用户线程发起read操作之后,立刻可以开始去做其它的事。而另一方面,从内核的角度,当它受到一个asynchronous read之后,它会立刻返回,说明read请求已经成功发起了,因此不会对用户线程产生任何block。然后,内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它read操作完成了。也说用户线程完全不需要实际的整个IO操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示IO操作已经完成,可以直接去使用数据了。
  也说在异步IO模型中,IO操作的两个阶段都不会阻塞用户线程,这两个阶段都是由内核自动完成,然后发送一个信号告知用户线程操作已完成。用户线程中不需要再次调用IO函数进行具体的读写。这点是和信号驱动模型有所不同的,在信号驱动模型中,当用户线程接收到信号表示数据已经绪,然后需要用户线程调用IO函数进行实际的读写操作;而在异步IO模型中,收到信号表示IO操作已经完成,不需要再在用户线程中调用iO函数进行实际的读写操作。
  注意,异步IO是需要操作系统的底层支持,在Java 7中,提供了Asynchronous IO。
  前面四种IO模型实际上都属于同步IO,只有后一种是真正的异步IO,因为无论是多路复用IO还是信号驱动模型,IO操作的第2个阶段都会引起用户线程阻塞,也是内核进行数据拷贝的过程都会让用户线程阻塞。
  六.两种高性能IO设计模式
  在传统的网络服务设计模式中,有两种比较经典的模式:
  一种是 多线程,一种是线程池。
  对于多线程模式,也说来了client,服务器会新建一个线程来处理该client的读写事件,如下图所示:

  这种模式虽然处理起来简单方便,但是由于服务器为每个client的连接都采用一个线程去处理,使得资源占用非常大。因此,当连接数量达到上,再有用户请求连接,直接会导致资源瓶颈,严重的可能会直接导致服务器崩溃。
  因此,为了解决这种一个线程对应一个客户端模式带来的问题,提出了采用线程池的方式,也说创建一个固定大小的线程池,来一个客户端,从线程池取一个空闲线程来处理,当客户端处理完读写操作之后,交出对线程的占用。因此这样避免为每一个客户端都要创建线程带来的资源浪费,使得线程可以重用。
  但是线程池也有它的弊端,如果连接大多是长连接,因此可能会导致在一段时间内,线程池中的线程都被占用,那么当再有用户请求连接时,由于没有可用的空闲线程来处理,会导致客户端连接失败,从而影响用户体验。因此,线程池比较适合大量的短连接应用。
  因此便出现了下面的两种高性能IO设计模式:Reactor和Proactor。
  在Reactor模式中,会先对每个client注册感兴趣的事件,然后有一个线程专门去轮询每个client是否有事件发生,当有事件发生时,便顺序处理每个事件,当所有事件处理完之后,便再转去继续轮询,如下图所示:

  从这里可以看出,上面的五种IO模型中的多路复用IO是采用Reactor模式。注意,上面的图中展示的 是顺序处理每个事件,当然为了提高事件处理速度,可以通过多线程或者线程池的方式来处理事件。
  在Proactor模式中,当检测到有事件发生时,会新起一个异步操作,然后交由内核线程去处理,当内核线程完成IO操作之后,发送一个通知告知操作已完成,可以得知,异步IO模型采用的是Proactor模式。