几种 IO编程比较

来源:互联网 发布:淘宝手提包 编辑:程序博客网 时间:2024/06/05 07:48

参考:
Netty权威指南第一版
Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

1. 传统的BIO模型

通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行处理,处理完之后,通过流返回应答给客户端,线程销毁。这就是典型的—请求—应答通信模型。

该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发量增加后,服务端的线程个数和客户端并发访问呈1:1的正比关系,由于线程是java虚拟机非常宝贵的系统资源,当线程数膨胀以后,系统的性能将急剧下降,随着并发访问量的继续增大,系统会发生线程堆溢出、创建新线程失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务。

2. 伪异步IO编程

对同步阻塞IO面临的问题,后来有人对它的线程模型进行了优化,后端通过一个线程池来处理多个客户端的请求接入,形成客户端个数M :线程池最大线程数N的比例关系,其中M可以远远大于N,通过线程池可以灵活的调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。

该方式避免了为每个请求都创建一个独立线程造成的线程资源耗尽。但是由于它底层的通信依然采用同步阻塞模型,因此无法从根本上解决问题。

分析:
如果每个read操作都阻塞,导致线程池很快饱和,将不能继续处理新的请求,导致服务不可用。

3. NIO编程

相关概念:

  1. 缓冲区Buffer

    • ByteBuffer:字节缓冲区
    • CharBuffer:字符缓冲区
    • ShortBuffer:短整型缓冲区
    • IntBuffer:整型缓冲区
    • LongBuffer:长整型缓冲区
    • FloatBuffer:浮点型缓冲区
    • DoubleBuffer:双精度浮点型缓冲区
  2. 通道

  3. 多路复用Selector

4. AIO编程

JDK1.7 提供了NIO2.0, 引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。异步通道提供两种方式获取操作结果:

  • 通多java.util.concurrent.Future类来表示异步操作的结果
  • 在执行异步操作的时候传入一个java.nio.channels

NIO2.0 的异步套接字通道是真正的异步非阻塞IO,它对应UNIX网络编程中的事件驱动IO(AIO),它不需要通过多路复用器(Selector)对注册的通道进行轮训操作即可实现异步读写,从而简化NIO的编程模型。

AIO是真正的异步非阻塞的,所以,在面对超级大量的客户端,更能得心应手。

5. 4种IO比较

概念澄清

  • 异步非阻塞IO

    很多人习惯将JDK1.4提供的NIO称为异步非阻塞IO,其实严格按照UNIX网络编程模型和JDK实现区分,实际上它只能被称为非阻塞IO,不能叫做异步非阻塞IO。在早期JDK1.4和1.5 update10版本之前,JDK的Selector基于select/poll模型实现,它是基于IO复用技术的非阻塞IO,不是异步IO。在JDK1.5 update10和Linux core2.6以上,Sun优化了Selector的实现,它在底层使用epoll替换了select/poll,上层的API没有变化,可以认为是JDK NIO的一次性能优化,但是它仍旧没有改变IO的模型。

    JDK1.7提供的NIO2.0才真正的异步IO。

  • 多路复用器Selector

    将Selector翻译成选择器体现不出Selector的功能和特点,翻译为多路复用器更为合适。

  • 伪异步

    伪异步IO完全来自实践,后端采用线程池来处理IO任务。

对比

IO模型对比

结语

具体代码可查阅《Netty权威指南》或者参考博客Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)