Java NIO
Java NIO 从 Java 1.4 版本开始引入的非阻塞 IO,用于替换标准 ( BIO,Blocking IO ) Java IO API 的 IO API 。
在Unix的IO模型里:
异步I/O 是指用户程序发起IO请求后,不等待数据,同时操作系统内核负责I/O操作把数据从内核拷贝到用户程序的缓冲区后通知应用程序。数据拷贝是由操作系统内核完成,用户程序从一开始就没有等待数据,发起请求后不参与任何IO操作,等内核通知完成。同步I/O 就是非异步IO的情况,也就是用户程序要参与把数据拷贝到程序缓冲区(例如java的InputStream读字节流过程)。
同步IO里的非阻塞 是指用户程序发起IO操作请求后不等待数据,而是调用会立即返回一个标志信息告知条件不满足,数据未准备好,从而用户请求程序继续执行其它任务。执行完其它任务,用户程序会主动轮询查看IO操作条件是否满足,如果满足,则用户程序亲自参与拷贝数据动作。
总结来说,在 Unix IO 模型的语境下:
同步和异步的区别:数据拷贝阶段是否需要完全由操作系统处理。
阻塞和非阻塞操作:是针对发起 IO 请求操作后,是否有立刻返回一个标志信息而不让请求线程等待。
所以说Java NIO 是同步非阻塞IO
对于服务端程序而言,一次IO过程分为两步 等待数据 和 将数据从内核拷贝到用户空间。
如果用BIO,客户端不发数据,服务端就一直阻塞等待数据;当客户端发数据完成,服务端还要阻塞将数据从内核拷贝到用户空间。所以是同步阻塞IO。
如果是NIO,客户端不发数据,服务端不会阻塞,但是要不断检查客户端发过来数据没,如果检查到有客户端发数据了,那就将数据从内核拷贝到用户空间;和BIO比只有在等待数据的时候是不需要阻塞的,所以是同步非阻塞IO。
NIO相较于BIO的优势就是等待数据的时候不用阻塞了,只需要检查有没有数据到达就可以。在程序实现上BIO全程只能客户端服务端一对一的阻塞进行通信,而NIO因为只需要检查有没有数据到达,所以在数据等待阶段可以客户端服务端多对一进行检查,但是服务端读数据的时候还是客户端服务端一对一进行读取。
如果是AIO,客户端不发数据,服务端不会阻塞;客户端一旦发数据,服务端所在的操作系统内核执行I/O操作把数据从内核拷贝到用户程序的缓冲区后通知服务端程序,服务端只要拿现成的数据就行。所以是异步非阻塞IO。
上图显示了五种IO模式,其中阻塞IO为BIO,非阻塞IO和IO复用为NIO,异步IO为AIO。信号驱动IO介于NIO和AIO之间,与NIO相比,信号驱动IO把等待数据的工作交给了操作系统完成,一旦有数据发送过来就通知应用程序,程序负责将数据从内核拷贝到用户空间;与AIO相比,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
Netty为啥去掉支持AIO?
一句话:AIO 并没有比 NIO 快多少,Netty已经有稳定的NIO实现了
java NIO 三大核心组件:Channel、Buffer、Selector
为什么使用 Netty
netty 底层基于 jdk 的 NIO ,我们为什么不直接基于 jdk 的 nio 或者其他 nio 框架?下面是我总结出来的原因
1.使用 jdk 自带的 nio 需要了解太多的概念,编程复杂
2.netty 底层 IO 模型随意切换,而这一切只需要做微小的改动
3.netty 自带的拆包解包,异常检测等机制让你从nio的繁重细节中脱离出来,让你只需要关心业务逻辑
4.netty 解决了 jdk 的很多包括空轮训在内的 bug
5.netty 底层对线程,selector 做了很多细小的优化,精心设计的 reactor 线程做到非常高效的并发处理
6.自带各种协议栈让你处理任何一种通用协议都几乎不用亲自动手
7.netty 社区活跃,遇到问题随时邮件列表或者 issue
8.netty 已经历各大rpc框架,消息中间件,分布式通信中间件线上的广泛验证,健壮性无比强大