一、阻塞?同步?
可能大家平常会经常听到这两个名词,但是没花太多心思详细了解,今天就来揭开这层面纱。
一次IO操作,以read方法举例,会经历两个阶段:
(1)等待数据准备(Waitingfor the data to be ready)
是否阻塞指的就是这一个阶段。
(2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
是否同步指的就是这一个阶段。
二、BIO
即blocking IO,阻塞式IO,大家最为熟悉的IO流,经常用于操作网络请求,文件读写之类。按读取类型可分为两大类:字符流,字节流。详情图如下:
IO流详情图附上普通I/O(BIO)的读流程图示:
BIO阻塞同步图当左边的应用进程发出了“system call”命令后,kernel首先进入第一阶段“wait for data”,然后再进入第二阶段“copying the data”,最后“return OK”返回到用户进程中,即BIO在两个阶段都是阻塞block的,阻塞并同步。
三、NIO
即non-blocking IO,也叫做new IO,因为是NIO是JDK 1.4的java.nio.*包中引入的新I/O库,目的是提高速度,也是对之前的BIO一个补充完善。
NIO的三个重点,重中之重的是:
1. channel(通道)
连接data数据与buffer缓存区的桥梁。
- 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
- 通道可以异步地读写。
- 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
2. Buffer(缓冲区)
用于和NIO通道进行交互。如图所示,数据是从通道读入缓冲区,从缓冲区写入到通道中的。
buffer3. Selector(选择器)
是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件,如此一个单独的线程可以管理多个channel,从而管理多个连接。
selector由于selector的原因,可以将NIO简单区分为两种:普通的NIO,和多路复用的NIO(加入了selector管理)。通过下面两张IO操作图示简单说明下两者区别:
NIO非阻塞同步图很明显的可以观测到NIO在IO操作的准备数据阶段时有一个轮询操作,会不停地发出“system call”到kernel轮询数据是否准备好,没准备好,应用进程可以处理其他事,准备好了之后在发出一个“system call”到kernel进行第二个阶段复制数据,这个过程是blocking的,所以NIO的特点就是在IO执行的第一阶段不会阻塞,但是在第二阶段将数据从内核拷贝到进程这个真是的IO操作还是会阻塞。
NIO多路复用图多路复用的NIO则是上述的普通NIO的补充,在并发量过大的情况下,不可能每个线程都要轮询自己的IO状态,这时就可以使用selector管理所有的IO通道channel,之用开启一个线程,便可解决成千上万的高并发问题(。◕ˇ∀ˇ◕)。
四、AIO
NIO 2.0引入了新的异步通道的概念,并提供了对异步文件通道和异步套接字通道的实现。(基于NIO)
Asynchronous IO,字面意思即异步的IO,完全不阻塞,那我们看看这个的read操作图示:
通过图示可以很清楚得发现,如果是AIO发起read操作之后,kernel收到请求后会立即响应应用进程application,所以应用进程完全可以做其他的事,不会造成任何的block。待kernel第一、二阶段都已经完成之后,会给应用进程发送一个signal,告诉它read操作已经完成。所以AIO的特点是在IO的两个阶段都不会发生阻塞,而是全权交给系统内核才完成,内核完成后通过信号告知应用进程即可。
五、各种I/O对比
属性\模型 | 阻塞BIO | 非阻塞NIO | 异步AIO |
---|---|---|---|
blocking | 阻塞并同步 | 非阻塞但同步 | 非阻塞并异步 |
线程数(server:client) | 1:1 | 1:N | 0:N |
复杂度 | 简单 | 较复杂 | 复杂 |
吞吐量 | 低 | 高 | 高 |
具体使用得依据业务的实际应用场景和性能需求而定,如果客户端很少,并发量不大,那么完全可以选择BIO,不过得加入线程池管理;相反要求并发较高的话,就应该采用NIO框架了。
六、简单总结
BIO、NIO、AIO概念认知:
- Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
- Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
- Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
BIO、NIO、AIO适用场景分析:
- BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
- NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
- AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
网友评论