阻塞(blocking)IO: 资源不可用时,IO请求一直阻塞,直到反馈结果(游数据或者超时)。
非阻塞(non-blocking)IO :资源不可用时,IO请求离开返回,返回数据标志资源不可用。
同步(synchronous)IO:应用阻塞在发送或接收数据状态,直到数据成功传输或失败返回。
异步(asynchronous)IO:应用发送或接收到数据后立刻返回,实际处理是异步执行的。阻塞/非阻塞:获取资源的方式
同步/异步:处理资源的逻辑设计
一,BIO
BIO, Blocking I/O 阻塞IO
一个线程只能处理一个网络连接
- 阻塞I/O(blocking I/O)模型,进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区中或者发生错误才返回。进程从调用recvfrom开始到它返回的整段时间内是被阻塞的。
二,NIO
Non-blocking I/O 非阻塞IO
NIO有三个核心组件:Buffer, Channel,Selector
1.Buffer 缓冲区
缓冲区的本质是一个可以写入数据的内存块(类似数组),然后可以再次读取。
内存块包含在NIO Buffer对象中,该对象提供了一组方法,可以更轻松的使用内存块
1)Buffer三个重要的属性
capacity容量:作为一个内存块,Buffer具有一定的固定大小,称谓容量
position位置:写入模式时代表写数据的位置,读取模式时代表读数据的位置
limit限制:写入模式,限制等于buffer容量,读取模式下,限制等于写入数据量
2)ByteBuffer内存类型
堆内内存和对外内存
堆内内存:非直接内存,heap
堆外内存:直接内存,direct
2.Channel通道
BIO模式
NIO模式
SocketChannel:用于建立TCP网络连接
ServerSocketChannel:用于监听新建的TCP网络连接
3.Selector选择器
selector选择器是NIO的一个组件,作用是检查一个或多个NIO通道,并确定哪些通道已经准备好进行读取或写入。实现单个线程可以管理多个通道,从而管理多个网络连接
一个线程可以使用selector监听多个channerl的不同事件
1)SelectionKey.OP_CONNECT:connect连接事件
2)SelectionKey.OP_ACCEPT:accept准备就绪
3)SelectionKey.OP_READ:read读取
3)SelectionKey.OP_WRITE:write写入
4.NIO与BIO工作模式的比较
BIO
一个客户端连接对应一个socket,一个socket对应一个线程
NIO
一个客户端连接对应一个channel, 多个channel注册到selector选择器,一个selector选择器对应一个线程
selector选择器工作原理图解:
5.reactor线程模型
NIO基于reactor线程模型实现
reactor是什么?
- 事件驱动
- 可以处理一个或多个输入源
- 通过多路复用将请求的事件分发给对应的处理器处理
单Reactor线程模型
此模型就是NIO最原始的做法,还是只有一个线程在处理所有的连接,会存在以下问题:
1.如果处理数据比较慢会造成堵车事件
2.并不能充分发挥服务器性能
基于工作线程的Reactor线程模型
此模型在单Reactor模型的基础上,将数据处理的工作交给单独的工作线程去做,解决了业务操作慢导致的堵车问题,但还是会有以下问题:
I/O处理会有瓶颈
多Reactor线程模型
多Reactor线程模型将接收客户端连接的工作单独放在一个线程,客户端连接进来以后,再分配另一个线程去处理IO操作,业务数据由单独的业务线程池去处理
三,AIO
从JDK 7版本开始,Java新加入的文件和网络io特性称为nio2(new io 2, 因为jdk1.4中已经有过一个nio了),包含了众多性能和功能上的改进,其中最重要的部分,就是对异步io的支持,称为Java AIO(asynchronous IO)。
因为AIO的实施需充分调用OS参与,IO需要操作系统支持、并发也同样需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。所以本文也附带介绍了Linux 2.6及以后版本新增的AIO特性(因为这跟Java AIO是对应关系)。
四,总结
BIO对比NIO
Java对BIO、NIO、AIO的支持:
-
Java BIO (blocking I/O): 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
-
Java NIO (non-blocking I/O): 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
-
Java AIO(NIO.2) (Asynchronous I/O) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,
BIO、NIO、AIO适用场景分析:
-
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
-
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
-
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。