Java NIO 简介

2018-02-02  本文已影响0人  AmyXYC

引自:http://blog.iluckymeeting.com/2018/02/02/JavaNioOverview/

Java NIO简介

Java 1.4开始引入了Java NIO以替换标准Java IO,标准Java IO是基于流(包括byte stream和character stream)的阻塞IO,而Java NIO是基于Channel和Buffer的非阻塞IO.

Java NIO中所有的IO操作都是基于Channel和Buffer的 Java NIO读写数据

Java NIO的所有IO操作都是非阻塞的,当线程要读取IO数据时,Channel会把数据读入Buffer,在读入的过程中线程不用阻塞等待,可以去处理别的任务,当数据读入完成后再回来继续处理;同理,当线程要写入数据时,Buffer中的数据被写入Channel,在写入的过程中线程不用阻塞。

Java NIO有三个核心构件:

Java NIO的所有IO操作都是通过Channel和Buffer完成的,IO读取是数据由Channel读入Buffer,IO写入是数据由Buffer写入Channel。Channel接口的继承结构如下: Channel interface

Java NIO中的几个核心Channel:

Buffer是一个项部抽象类: Buffer

Buffer支持全部的基本类型byte、char、double、float、int、long、short,对应的提供了

一个线程要管理多个Channel连接就要依赖Selector,当然这种情况下一般是有多个打开的连接,并且各连接要处理的IO事件都比较轻量化

Thread-Selector-Channel
Channel创建后会注册到Selector上,Selector的select()方法调用后会阻塞,等待注册的多个Channel有事件到达,然后select()方法返回,线程继续处理。

Java NIO与Java IO比较

Java IO Java NIO
基于Stream 基于Buffer
阻塞IO 非阻塞IO
Selector

基于Stream Vs. 基于Buffer

Java IO是基于Stream的,数据读取操作是由Stream中读取一个或多个byte,每个byte只能由Stream中读取一次,如果要重复使用读取的数据只能是将Stream读出的数据缓存起来。

Java NIO是基于Buffer的,数据读取操作会将Channel中的数据读入Buffer,之后线程可以从任意位置开始使用Buffer里的数据,并且可以重复读取Buffer里的数据,方便灵活。处理Buffer里的数据有两个注意点:

阻塞IO Vs. 非阻塞IO

Java IO基于Stream的读写操作是阻塞的,发起读写操作后线程会阻塞直到读写完成;Java NIO基于Channel和Buffer的读写操作是非阻塞的,发起读操作时,数据会由Channel读入Buffer,发起写操作时,数据会由Buffer写入Channel,线程不必阻塞等待。

Selector

Java NIO之所以能做到非阻塞读写操作,是因为有Selector的存在,当Channel连接建立时会注册到Selector上,线程通过Selector来操作Channel完成数据读写,Selector阻塞在select()方法上,当有Channel达到就绪状态时,Selector会选取这个Channel进行读写操作,这个过程中线程不必阻塞,可以同时去处理别的任务。

Java IO使用 Vs. Java NIO使用

假设要传输以下内容:

Name:张三
Age:34
Addr:北京市

Java IO的处理是:

InputStream input = ... ; // get the InputStream from the client socket
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String nameLine   = reader.readLine();
String ageLine    = reader.readLine();
String addrLine  = reader.readLine();

Java IO读操作首先会阻塞在第一个reader.readLine()操作上,直到第一行数据读取完成,接着阻塞到第二个reader.readLine()方法上,直到第二行数据读取完成,接着阻塞在第三个reader.readLine()方法上,直到第三行数据读取完成。由此可见Java IO操作虽然是阻塞的,但是可以明确的知道数据读取的进度和内容,数据处理逻辑相对简单。

Java NIO的处理是:

ByteBuffer buffer = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buffer);
while(! bufferFull(bytesRead) ) {
    bytesRead = inChannel.read(buffer);
}

当inChannel.read(buffer)被调用时,只能确定Channel中有数据读入了Buffer,但是并不知道是否所有数据都已经读入了Buffer中,只好不断检测bufferFull()方法,直到所有Buffer被填满.
由此可见Java NIO的读写操作虽然不会阻塞线程,但是数据处理逻辑相对较复杂。

综上所述,Java NIO的非阻塞特性可以让一个线程轻松管理多个Channel连接,但是数据处理的代价较Java IO要更大,所以如果要管理大量连接并且每个连接要处理的数据量不大,则可以选择Java NIO;如果连接数量不多,但是每个连接占用的带宽很大,则可以选择Java IO。

上一篇 下一篇

猜你喜欢

热点阅读