Java的NIO教程
NIO 官方名称叫做 New IO,在 JDK 1.4 中相对于 BIO 的新 IO。但是也有很多人称之为 NON-BLOCKING IO。和 BIO 比较的话,叫做非阻塞 IO。底层使用的是 IO 复用模型(同步非阻塞)。它是面向缓冲区的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。
NIO的描述
NIO 是在
缓冲区Buffer
Buffer 是一个对象,所有的数据都是使用缓冲区处理的。读取数据的时候,会先到缓冲区里面读取数据,写数据的时候,会将数据写入缓冲区。任何时候通过 NIO 操作数据时,都是操作缓冲区里面的数据。
缓冲区的实际面目就是一个数组,但是它呢又不是一个简单的数组,Buffer 类和它的子类提供了对数组进行封装的方法,更好风方便的操作这些数据。它有以下缓冲区:
ByteBuffer:字节缓冲区
CharBuffer:字符缓冲区
ShortBuffer:短整型缓冲区
IntBuffer:整形缓冲区
LongBuffer:长整型缓冲区
FloatBuffer:浮点型缓冲区
DoubleBuffer:双精度浮点型缓冲区
我们可以看到,
通道Channel
和 Buffer 一样,Channel 也是一个对象,可以通过 Channel 读取和写入数据。通道与流的不同之处在于就好比我们日常生活中的公路,流就是单行道,它只能往一个方向行走,一个流的话必须是 InputStream 或者 OutPutStream 的子类。而 Channel 就像是双行道,它可以用于读或者写,或者读和写同时进行,不会相互影响。
在 NIO 中,所有的 IO 操作都是从 Channel 开始的,它和 Buffer 的关系如下:
在通道 Channel 中,我们平时用到比较多的 Channel 实现有:
FileChannel:文件 IO
DatagramChannel:网络 IO
SocketChannel:网络 IO
ServerSocketChannel:网络IO
多路复用器Selector
多路复用器 Selector 提供了选择已经就绪的任务的能力。之前我们讲的 Channel 它们会注册到 Selector 上面。然后 Selector 会不停的轮询注册在它上面的 Channel,如果某个 Channel 上面发生读或者写事件,这个 Channel 就处于了就绪状态,会被 Selector 轮询出来,然后通过 SelectionKey(一个特定的通道对象和一个特定的选择器对象之间的注册关系) 可以获取到就绪的 Channel 集合,进行后续的 IO 操作。
一个多路复用器 Selector 可以同时轮询多个 Channel,它可以使用更少的线程来处理通道信息。原理图如下:
关系
我们对 NIO 核心的三个元素有了一个大体的了解,知道了每个元素的实际作用,它们之间的大体关系如下:
上面的流程大致如下:
Channel 调用 register 方法,注册到 Selector 上面,会被分配 SelectionKey。它将 Channel 和 Selector 之间建立了关系。
Selector 上面会有一个死循环,监听其上面注册到 channel 是否有读或者写事件。Selector 会根据 SelectedKey 获取里面相应的 Channel,并且处理里面的数据。
处理完成后,将 SelectedKey 删除,监听等待下次事件的到来。
NIO总结
本章节,我们了解了 NIO 的三个重要的元素,Buffer、Channel 和 Selector。它们相辅相成,为 NIO 高效通信提供了基础保障。NIO 是面向缓冲的,所有的数据操作都会在 Buffer 中,它是通过通道 Channel 将数据流通,通过 Selector 选择器来监听 Channel 里面的事件变化来读取数据进行操作。