【IO专栏】Java OIO NIO通信对比分析【002】

在1.4版本之前,Java IO类库是阻塞IO;从1.4版本开始,引入了新的异步IO库,被称为Java new IO 类库,new IO 类库的目标,就是要让Java支持非阻塞IO,基于这个原因更多人喜欢称JAVA NIO为非阻塞IO(Non-Block IO),称为“老的”阻塞式JAVA IO为OIO (Old IO).总体上说,NIO弥补了原来面向流的OIO同步阻塞的不足,它为标准Java代码提供了高速的,面向缓冲区的IO。

Java NIO由以下三个核心组件组成:

Channel(通道)

Buffer (缓冲区)

Selector(选择器)

如果理解了第一章的四种IO模型,大家一眼就能识别出来,Java NIO,属于第三种模型--IO多路复用模型。当然,Java NIO组件,提供了统一的API,为了大家屏蔽了底层的不同操作系统的差异。

后面,我们会对以上三个Java NIO的核心组件,展开详细介绍。先来看看Java 的NIO和OIO的简单对比。

 

NIO和OIO的对比

在Java中,NIO和OIO的区别,主要体现在三个方面:

(1)OIO面向流(Steam Oriented)的,NIO是面向缓冲区(Buffer Oriented)

何谓面向流,何谓面向缓冲区呢?

OIO是面向字节流,或字符流的,在一般的OIO操作中,我们以流式的方式顺序地从一个流(Steam)中读取一个或多个字节,因此,我们不能随意的改变读取指针的位置。而在NIO操作中则不同,NIO引入了Channel(通道)和Buffer(缓冲区)的概念。读取和写入,只需要从通道中读取数据到缓冲区中,或将数据从缓冲区中写入到通道中。NIO不像OIO那样是顺序操作,可以随意地读取Buffer中任意位置的数据。

(2)OIO的操作是阻塞的,而NIO的操作是非阻塞的。

NIO是如何做到非阻塞的?大家都知道,OIO操作都是阻塞的,例如,我们调用了一个read方法读取一个文件的内容,那么调用read的线程会被阻塞住,直到read操作完成。

而在NIO的非阻塞模式中,当我们调用read方法时,如果此时有数据,则read读取数据返回;如果此时没有数据,则read直接返回,而不会阻塞当前线程。NIO的非阻塞,是如何做到的?其实上一章答案已经揭晓了,NIO使用了通道和通道的多路复用技术。

(3)OIO没有选择器(Selector)概念,而NIO有选择概念。

NIO的实现,是基于底层的选择器的系统调用。NIO的选择器,需要底层操作系统提供支持。而OIO不需要用到选择器。

 

通道(channel)

在OIO中,同一个网络接连会关联到两个流:一个输入流(Input Stream)另外一个输出流(OutputStream)。通过两个流,不断的进行输入和输出操作。

在NIO中,同一个网络链接使用一个通道表示,所有的NIO的IO操作都是从通道开始的。

一个通道类似于OIO中的两个流的结合体,既可以从通道读取,也可以向通道写入。

Selector选择器

什么是IO多路复用?指的是一个进程/线程可以同时监控多个文件描述符(一个网络连接,操作系统底层使用一个文件描述符来表示),一旦其中的一个或多个文件描述符可读,或者可写,系统内核就通知进程/线程。在Java应用层面上,如何实现对多个文件描述符号的监视呢?需要用到一个非常重要的Java NIO组件--Selector 选择器。

选择器的神奇功能是什么?它是一个IO事件的查询器。通过选择器,一个线程可以查询多个通道的IO事件的就绪状态。

实现IO多路复用,从具体的开发层面来讲,首先要把通道注册到选择器中,然后通过选择器内部的机制,可以查询(Select)这些注册的通道是否有已经就绪的IO事件(例如可读,科协,网络连接完成等)

一个选择器只需要一个线程进行监控,换句话说,我们可以简单的使用一个线程,通过选择器去管理多个通道。这是非常高效的,这种高效来自于Java的选择器组件Selector,以及背后的操作系统底层的IO多路复用的支持。

与OIO相比,使用选择器的最大优势:系统开销小,系统不必为每一个网络连接(文件描述符)创建线程,从而大大的减少系统的开销。

 

缓冲区(Buffer)

应用程序与通道(Channel)主要的交互操作,就是进行数据的read读和write写。为了完成如此大任,NIO为大家准备了第三个重要组件--NIO Buffer (NIO 缓冲区)。通道的读取就是将数据从通道读取到缓冲区中;通道的写入就是将数据从缓冲区中写入到通道中。

缓冲区的使用,是面向流的OIO所没有的,也是NIO非阻塞的重要前提和基础之一。

你可能感兴趣的:(Java,IO,NIO底层原理与使用)