Java的NIO

Java的NIO教程

NIO 官方名称叫做 New IO,在 JDK 1.4 中相对于 BIO 的新 IO。但是也有很多人称之为 NON-BLOCKING IO。和 BIO 比较的话,叫做非阻塞 IO。底层使用的是 IO 复用模型(同步非阻塞)。它是面向缓冲区的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。

NIO的描述

NIO 是在 JDK 1.4 的时候引入进来的,它弥补了原先 BIO 的不足,想更好的了解 NIO,我们要先了解缓冲区(Buffer)、通道(Channel)和多路复用器(Selector)的概念。

缓冲区Buffer

Buffer 是一个对象,所有的数据都是使用缓冲区处理的。读取数据的时候,会先到缓冲区里面读取数据,写数据的时候,会将数据写入缓冲区。任何时候通过 NIO 操作数据时,都是操作缓冲区里面的数据。

缓冲区的实际面目就是一个数组,但是它呢又不是一个简单的数组,Buffer 类和它的子类提供了对数组进行封装的方法,更好风方便的操作这些数据。它有以下缓冲区:

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

我们可以看到,Java 的基本类型 中,除了 boolean 类型没有缓冲区,其他的基本类型都有与之对应的缓冲区。它们的关系如下:

07 NIO Buffer.png

通道Channel

和 Buffer 一样,Channel 也是一个对象,可以通过 Channel 读取和写入数据。通道与流的不同之处在于就好比我们日常生活中的公路,流就是单行道,它只能往一个方向行走,一个流的话必须是 InputStream 或者 OutPutStream 的子类。而 Channel 就像是双行道,它可以用于读或者写,或者读和写同时进行,不会相互影响。

在 NIO 中,所有的 IO 操作都是从 Channel 开始的,它和 Buffer 的关系如下:

08 Channel.png

在通道 Channel 中,我们平时用到比较多的 Channel 实现有:

  • FileChannel:文件 IO
  • DatagramChannel:网络 IO
  • SocketChannel:网络 IO
  • ServerSocketChannel:网络IO

多路复用器Selector

多路复用器 Selector 提供了选择已经就绪的任务的能力。之前我们讲的 Channel 它们会注册到 Selector 上面。然后 Selector 会不停的轮询注册在它上面的 Channel,如果某个 Channel 上面发生读或者写事件,这个 Channel 就处于了就绪状态,会被 Selector 轮询出来,然后通过 SelectionKey(一个特定的通道对象和一个特定的选择器对象之间的注册关系) 可以获取到就绪的 Channel 集合,进行后续的 IO 操作。

一个多路复用器 Selector 可以同时轮询多个 Channel,它可以使用更少的线程来处理通道信息。原理图如下:

09 selector.png

关系

我们对 NIO 核心的三个元素有了一个大体的了解,知道了每个元素的实际作用,它们之间的大体关系如下:

10 nio 整体.png

上面的流程大致如下:

  1. Channel 调用 register 方法,注册到 Selector 上面,会被分配 SelectionKey。它将 Channel 和 Selector 之间建立了关系。
  2. Selector 上面会有一个死循环,监听其上面注册到 channel 是否有读或者写事件。Selector 会根据 SelectedKey 获取里面相应的 Channel,并且处理里面的数据。
  3. 处理完成后,将 SelectedKey 删除,监听等待下次事件的到来。

NIO总结

本章节,我们了解了 NIO 的三个重要的元素,Buffer、Channel 和 Selector。它们相辅相成,为 NIO 高效通信提供了基础保障。NIO 是面向缓冲的,所有的数据操作都会在 Buffer 中,它是通过通道 Channel 将数据流通,通过 Selector 选择器来监听 Channel 里面的事件变化来读取数据进行操作。