简介
本文介绍Java的IO模型:BIO、NIO、AIO的区别。
这也是面试常问的问题。
BIO、NIO、AIO区别
项 | BIO (Block IO) | NIO (New IO) | AIO(Asynchronous I/O) |
JDK版本 | 所有版本 | JDK1.4及之后 | JDK1.7及之后 |
异步/阻塞 | 同步阻塞。 一个连接一个线程。线程发起IO请求,不管内核是否准备好IO操作,从发起请求起,线程一直阻塞,直到操作完成。 数据的读取写入必须阻塞在一个线程内等待其完成。 | 同步阻塞/非阻塞。 一个请求一个线程。客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。用户进程也需要时不时的询问IO操作是否就绪,这要求用户进程不停的去询问。 | 异步非阻塞。 一个有效请求一个线程。用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。 |
使用场景 | 已成为解决高并发与大量连接、I/O处理问题的有效方式。 比如:Netty、多人聊天室。 | 适用于连接数目多且连接比较长(重操作)的架构。例如:相册服务器。 目前 AIO 的应用还不是很广泛。 |
为什么Netty用NIO?
Netty 之前也尝试使用过 AIO,不过又放弃了,因为AIO在性能、内存占用上,实际不如NIO。Netty作者的原话如下:
Not faster than NIO(epoll) on unix systems (which is true) 。(在UNIX系统上不比NIO快)
There is no daragream support (不支持数据报)
Unnecessary threading model(too much abstraction without usage) (不必要的线程模型)
详细分析:
- Linux上,AIO底层实现仍使用Epoll,没有很好的实现AIO,因此性能上没有明显优势,而且被JDK封装了一层不容易优化。
- Netty整体架构是基本reactor模型,而AIO是proactor模型,混合在一起会比较混乱。
- AIO有个缺点:接收数据需要预先分配缓冲区,而不是NIO那种需要接收时才需要分配缓存,所以对连接数量非常大但流量小的情况,会浪费内存。
- Linux上AIO不够成熟,处理回调的结果速度跟不上处理需求,供不应求,造成处理速度有瓶颈。比如:外卖员太少,顾客太多。
另外:NIO是一种基于通道和缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存(区别于JVM的运行时数据区),然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的直接引用进行操作。这样能在一些场景显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。
实例
BIO
略。
NIO
待填充。
AIO
略。
请先
!