面试官:介绍一下常见的io模型

38 阅读1分钟

前置概念

Java本身不能直接读取数据,调用read方法读取网络数据需要通过调用操作系统层面的函数来调取数据。当调用一次 channel.read 或 stream.read 后,会切换至操作系统内核态来完成真正数据读取,而读取又分为两个阶段,分别为:

  • 等待数据阶段
  • 复制数据阶段 image.png

阻塞io

对于阻塞io模型来说,当用户进程调用read方法时,如果操作系统层面连接没有建立,那么进程就会阻塞,等待连接建立,复制数据,然后才切换回进程态。如果一直没有数据抵达,那么进程就会一直阻塞。

这种模型显然不适合使用。

非阻塞io

非阻塞io模型,在调用read方法以后做了优化,具体来说就是将read放到一个死循环中,假如调用read没有数据,立马返回,然后再次调用。

这种io模型显然非常消耗资源,因为有很多次的循环是没有意义的。

多路复用

仔细观察上面的阻塞和非阻塞io,都是用户进程主动监听客户端的动作,等待处理。 能不能采用一种进程通知的方式呢?

当客户端有事件需要被处理的时候,发出通知,内核空间通知用户进程的selector来处理。用户进程的selector负责监听用户的事件。有事件时不阻塞,没有事件时就阻塞。 以事件为单位来处理,这样就可以做到单线程,同时高效地处理事件。

Redis在4.0版本前就是采用多路复用模型。 image.png