JAVA - IO模型
Posted hpzhu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA - IO模型相关的知识,希望对你有一定的参考价值。
本章内容
1 同步,异步,阻塞,非阻塞的概念
2 五种IO模型:阻塞式IO,非阻塞式IO,多路复用IO,信号驱动IO,异步IO 各自的特点
同步,异步,阻塞,非阻塞(注意:这里是从用户线程和内核层面来介绍概念的)
同步和异步(描述的是用户线程与内核的交互方式 - 消息的通信机制)
1 同步 用户线程发起IO后需要等待
2 异步 用户线程发起IO请求后仍然继续执行,当内核操作完成后会通知用户线程,或者调用用户线程注册的回调函数
阻塞和非阻塞(描述的是程序等待调用结果是的状态 - 调用者的状态)
1 阻塞 在调用结果返回之前,调用者的执行线程会挂起,线程不能做其它事情,只有等待结果返回才能往下执行
2 非阻塞 IO操作被调用后立即返回调用者一个状态值,无需等待IO操作彻底完成
IO模型
介绍
操作系统为了安全,将内存空间分成了用户空间和内核空间,用户进程无法直接操作底层硬件,只能将请求提交给CPU,由CPU去执行
进程(线程)将请求提交给CPU,等待CPU返回数据(这是一个两段式的过程)
1 等待数据准备:内核从IO设备将数据拷至内存空间的Buffer中
2 内核将数据从内部的Buffer中拷贝至进程空间
注意:内核在IO操作时,会为每一个IO设备维护一个Buffer,等待数据输入到Buffer,从Buffer复制到进程内存空间,都需要时间,根据等待模式可以分为:
1 blocking IO 阻塞式IO (两段都阻塞)
2 nonblocking IO 非阻塞式IO (第一段不阻塞,第二段阻塞)
3 IO multiplexing IO复用 (两段都阻塞)
4 signal driven IO 信号驱动IO (第一段不阻塞,第二段阻塞)
5 asynchronus IO 异步IO (两段都不阻塞)
下面将对以上五种模型做一个详细的介绍
阻塞式IO
1 用户线程在读写时阻塞,系统调用不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回
如图:
1 recvfrom 发起系统调用,当内核无数据报准备好时,要等待数据准备 (第一段) 应用进程阻塞
2 当内核数据准备好后,将数据拷贝至用户空间(第二段)应用进程阻塞 拷贝完成后,返回成功,让用户进程去处理数据包,此时阻塞结束,将控制权移交给应用进程
2 缺点
用户进程在IO过程中被阻塞,不能做任何事情,对CPU的资源利用率不高
非阻塞式IO
1 用户线程不断发起IO请求,数据未到达前时系统返回一个状态值,数据到达后才真正读取数据(需要用户线程不断确定数据报是否已经准备好)
如图:
1 当用户进程recvfrom发起一个系统调用,内核无数据包准备好时会返回一个EWOULDBLOCK状态,当用户进程不知道内核有没有准备好数据,需要通过不断轮询的方式去确定数据报是否准备好(这个过程用户进程是非阻塞的)
2 当内核准备好数据后,内核将数据拷贝至进程空间(用户进程阻塞)
2 缺点
用户进程每次请求IO都可以立即返回,但是为了拿到数据,需不断地轮询,无谓地消耗了大量CPU
IO多路复用(模式介绍不是很详细,将在后续BIO,NIO中进行详细介绍)
1 用户先将需要进行IO操作的socket添加到select中,然后等待阻塞函数select返回,当数据到达后,socket被激活,select返回,用户线程就能接着发起read请求(注意:阻塞的是select)
这里涉及到操作系统底层提供的 select,poll,epoll三种机制,这里举例为select(将在后续NIO中介绍此种模式的使用)
如图:
I/O多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作
2 优点
可以在单个线程/进程中处理更多的连接
系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销
信号驱动IO
如图:
1 先开启套接字的驱动式IO功能,并通过sigachtion系统调用安装一个信号处理函数,该系统调用立即返回,进程继续工作,当数据报准备好时,内核为该进程产生一个SIGIO信号 (第一段不阻塞)
2 接收到信号后,再次发起系统调用,由内核将数据包拷贝至用户空间(第二段阻塞)
异步IO
1 工作机制 告知内核启动某个操作,并让内核在整个操作完成后通知我们
如图:
1 应用进程发起系统调用,内核立即返回一个状态,此时进程继续执行
2 当内核准备好数据,并将数据包拷贝至用户空间后,通知进程处理 (两段都不阻塞)
总结:
1 阻塞式IO:用户进程发起系统调用,阻塞用户进程,内核处理数据报,当两段全部处理完成后,返回成功指示,再由用户进程去处理数据报
2 非阻塞式IO:用户进程发起系统调用,当内核数据报未准备好时,返回一个状态给用户进程,用户进程继续执行,未阻塞,但需要发起轮询,不断地询问内核数据报是否准备好,当发现数据报已准备好时,阻塞用户进程,由内核将数据报拷贝至用户空间,拷贝完成后,返回成功指示,由用户进程去处理
3 多路复用IO:用户进程将IO请求注册到select中,用户进程继续执行,select发起系统调用,内核做数据准备,当内核准备好数据时,返回相应用户进程的可读指示,用户进程再发起系统调用,用户进程阻塞,内核将数据报拷贝至用户空间,拷贝完成后,返回成功指示,由用户进程去处理
4 信号驱动IO:用户进程发起系统调用,当内核数据报未准备好时,返回一个状态给用户进程,用户进程继续执行,未阻塞,当内核准备好数据时,通过信号通知用户进程,用户进程再发起系统调用,用户进程阻塞,内核将数据报拷贝至用户空间,拷贝完成后,返回成功指示,由用户进程去处理
5 异步IO:用户进程发起系统调用,当内核数据包未准备好是,返回一个状态给用户进程,用户进程继续执行,未阻塞,当内核准备好数据,并将数据拷贝至用户空间后,通知用户进程去直接处理数据报
以上是关于JAVA - IO模型的主要内容,如果未能解决你的问题,请参考以下文章