来谈一谈我所理解的Java中的IO

650 阅读5分钟

I/O是Java语言中的一个重要的组成部分,平时的开发过程中也是使用频率很高的一个模块。这篇文章并不是讨论Java中I/O的体系,仅仅重点来讨论下BIO和NIO。

什么是I/O

在学习Java的很长一段时间中,我所理解的I/O仅仅是用来操作文件的。

实际上I/O是input/output的意思,就是输入输出操作。处理器访问任何寄存器和 Cache 等封装以外的数据资源都可以当成 I/O 操作。比如一次文件操作就是一次磁盘io,一次网络请求就是一次网络io,还有对数据库的读写也是io操作。

正因为I/O操作遍布应用的每一处,所以I/O的性能也就格外的重要。但不幸的事目前的多数系统的性能瓶颈都是出现的I/O这一块,为了提高I/O性能目前有很多的方案。

  • 系统架构中添加缓存层。
  • 实时计算更多的放到内存中完成(spark)
  • 更换更好的硬件(固态硬盘)
  • 优化I/O模型,Java中引入NIO

这篇文章讨论的就是最后一个:Java中的I/O模型。

理解I/O

要理解I/O的模型不同之处,首先来了解I/O的运作流程。

内核调用

我们的应用都是运行在操作系统上的,操作系统的作用是用于管理硬件资源和为应用程序开发人员提供良好的环境,但是计算机系统的各种资源是有限的,操作系统还需要保证每一个进程都能安全的执行。为了保证对资源的访问的安全性,处理器设有两种模式:用户模式和内核模式。一些容易发生安全问题的操作都被限制在只有内核模式下才可以执行,例如I/O操作等。

我们的应用程序是运行在用户模式下的,当应用程序需要实现内核模式下的指令时(如从磁盘读取文件),需要先向操作系统发送调用请求。操作系统收到请求后,执行系统调用接口,使处理器从用户态切换到内核态,开始执行相应的请求。当处理器处理完系统调用操作后,操作系统会再次将处理器从内核态切换到用户态,继续执行用户程序。

系统调用

BIO

BIO也就是Block Input Output,阻塞I/O模型,这是最常用的一种I/O模型,一般在缺省的情况下都是使用的这种模型。这种模型以上面图中的步骤来说的话就是所有的步骤都是顺序进行的。

BIO模型

当处理器从用户态切换到内核态时,用户态的线程就只能阻塞在那里一直等待数据返回(或发生错误),当内核准备好数据后,用户态线程需要等将数据拷贝到用户空间缓冲区时才能继续往下执行。

这种模型的好处在于简单,易于理解和实现。但缺点在于线程大量时间被阻塞,浪费了资源。

而且BIO的这种模型并不适用于在大并发的请求环境下,因为客户端的每一个socket请求在服务端都会有一个相应的socket与其对应用于收发数据。只要客户端不断开链接那服务端的socket也会一直存在,这样在并发量高的情况下很快资源就会被耗尽。

阻塞IO

这样每一个客户端的请求服务端都会有一个线程来处理。

NIO

BIO的效率是比较低下的,主要原因在于一是阻塞的时间太长,二是大量请求下服务器资源容易被击穿。基于这样的问题,Java在jdk1.4的时候推出了Java中新的I/O模型-NIO。

NIO也即是Non-Blocking Input Output(也被成为New IO),NIO和BIO最大的不同在于等待内核准备好数据的这一过程。

BIO中内核准备数据时会一直阻塞直到数据返回活着发生错误,而NIO中发起系统调用后就立即返回,该线程可以去做别的事情,等待数据的这一过程由原来的阻塞等待在NIO中被轮询检测替代。

非阻塞IO

应用程序发起需要系统调用参与的请求后立刻返回而无需等待数据准备好。返回后的进程可以处理一些别的事情,每个一定的时间轮询的检查内核的数据是否已经准备好。等数据准备好后接着处理数据。这样在内核准备数据的阶段,进程不用一直等待而被浪费。

同时还引入来I/O多路复用模型来提高效率,多路复用模型的好处在于每一个请求并不会立刻给其分配一个处理线程,而是将其注册到Selector上,等待请求时间就绪后再执行,基本模型如下:

多路复用

每一个客户端请求都会创建一个channel,每一个channel都被注册到Selector上,channel有多个状态如可读可写等。selector会轮询被注册在它身上的channel,当有channel的状态发生改变时就将其放入线程池中执行。这样由一个线程就可以管理成千上万的请求,当有客户端请求进来后不会阻塞,注册到selector上即可。

AIO

AIO即是(Async IO)-异步IO,AIO和NIO的不同之处在于内核准备好数据后应用程序如何进行感知。

NIO中是有应用程序每隔一定的时间就去检查是否准备好数据。而AIO是实现来回调机制,当数据准备好后由操作系统来回调我们的接口通知数据已经准备好可以接着处理下面的流程了。所以说NIO是同步的,而AIO是异步的。

参考文档

Netty权威指南 第二版