IO模型分为同步阻塞,同步非阻塞,同步多路复用,异步阻塞(没有此情况),异步非阻塞.
当用户调用chanel.read和stream.read后,会切换到操作系统内核态来完成真正的数据读取。而数据读取又分为两个阶段:
- 等待数据阶段
- 复制数据阶段
- 阻塞IO(同步模式):
调用read后,网络上还没数据过来,read方法就阻塞住,一直等到linux内核有数据返回,并复制数据结束才继续执行。
- 非阻塞IO(同步模式):
调用read后,网络上还没数据过来,立即返回,循环多次调用,直到有数据为止,然后进行复制数据(复制数据仍然是阻塞的),最后返回,并继续后续逻辑
PS:只有等待数据阶段非阻塞,复制数据阶段还是阻塞的.而且每次调用read都涉及到用户态和内核态的切换,比较耗性能。 - 同步多路复用(也是同步模式)
多路复用调用select()后,其实两个阶段也是阴塞的
如下图所示:
多路复用与阻塞IO的区别:阻塞IO在调用read()方法阻塞后,即使其他客户端连接过来,他也要等到当前连接复制完数据,返回后才能进行处理。只能A连接请求过来,复制完A连接的数据,read方法返回;再处理下B连接请求,读取B连接的数据,read方法返回。
如下所示:
多路复一次用监听了多个channel的多个事件,select()方法阻塞后,只要有任何一个channel的任何一个事件触发,它就会把多个chanel的多种事件一次性获取回来,进行处理,并不只是一次处理一个连接的各种事件。
如下图所未,调用select()方法等待事件后,因为某个事件触发返回,一次性获取了c1的read(),c2的accept(),c3的read()方法,后续的建立连接,复制数据也基于这个个selectKey进行,并不局限于某个channel. - 信号驱动
同步VS异步:
- 同步:一个线程调用某个功能,并在调用当时就能拿到结果
- 异步:一个线程调用某个功能,当时并没有拿到结果,而是后续某个时候,系统通过回调等方式,才结果通知给线程。
如下图