Java IO 流简介

IO 在 Java 中占据了很重要的位置。在 Java 中,Java 可以分为以下几类:

  • BIO
  • NIO
  • AIO

上面的 IO 可以根据分类分成同步阻塞IO、同步非阻塞 IO 和异步非阻塞 IO。

BIO 就是 Blocking IO,也就是同步阻塞 IO。java.io 中的所有 API 和 java.net 中的部分 API 都算是同步阻塞型 API。

在 Java1.4 中添加了 NIO( Non-blocking IO),也就是 同步非阻塞 IO,在 NIO 中添加了 Channel 等特性,通过这些可以构建多路复用的、同步非阻塞的 IO 程序。

在 Java1.7 中添加了 NIO2,也被称之为 AIO(Asynchronous IO),这就是异步非阻塞的方式。异步 IO 操作是基于事件和回调机制实现的。

BIO 基础

java.io 中的 API 使用起来简单、直观,但是 IO 的效率和扩展性有着局限性。下图是对 java.io 中的主要的 API 做的一个分类:

java.io 中的 API 大体上可以分成两类,一类是字符流,一类是字节流。字节流类的 API 更适合操作整个文件,比如图片文件。字符流类的接口是直接操作字符的,这类的接口更适合从文件中读取或者写入文本信息。

在 java.net 中,Socket通信等相关的 API 也都是 BIO 。

NIO 基础

对于一个传统基于 BIO的 CS(Client-Server) 应用程序,为了更高的并发量,那么就需要减少线程被创建的次数和数量。这个时候就需要使用线程池的机制来提高并发量,通过一个固定大小的线程池,来负责管理线程,避免线程被反复的创建和销毁。

但是这种方案还是不能够彻底解决问题,用户数量不多时,这种模式可以很好的工作,如果并发量很高,那这样的方案还是有很大的问题的,因为线程的上下文切换的过程所耗费的时间在高并发的会非常的明显。这种 BIO 的程序可以表示如下:

所以在依赖 java.io 相关的 API 本身已经没有办法可以解决这些问题了,这也是 NIO 被设计出来的目的。

在 NIO 引入了多路复用的机制,一种与 BIO 完全不同的思路。在具体说明 NIO 的思路之前,NIO 中三个关键的概念需要先理解一下:

  • Buffer: NIO 中的数据容器,除了布尔类型,其他所有的原始数据都有相应的实现
  • Channel: NIO 中用来支持批量 IO 操作的一种抽象,相比于 FileSocket 的实现,Channel 的实现则更加接近操作系统的底层,这也就使得 NIO 能够充分使用操作系统的底层。
  • Selector: Selector 是 NIO 实现多路复用的基础,每一个 Channel 都需要注册在一个 Selector 上,Selector 可以实时监测 Channel 的状态,进而实现单线程对多个 Channel 的管理。

在同样的一个 CS 应用程序来说,NIO 比 BIO 更有效率的地方就是利用单线程轮询的方式来确定需要处理的 Channel,整体上是同步非阻塞的,可以避免在大量客户端连接时频繁切换线程带来的问题。 使用 NIO 来实现这个应用程序可以设计如下:

NIO2(AIO)

在 Java1.7 中,又添加了一种新的 IO,利用事件和回调来处理消息的接收和发送。AIO 是一种异步非阻塞的 IO 机制。

AIO 的基本抽象与 NIO 非常相似。与 NIO 不同的地方在于不再是通过轮询的方式去确定是否继续后续的操作,而是通过事件机制来实现这一点。

(完)

参考文献

  1. 极客时间专栏 Java 核心技术36讲
  2. Java 官方文档

微信公众号

© 2018 ray