美文网首页
Java NIO 简介

Java NIO 简介

作者: AmyXYC | 来源:发表于2018-02-02 17:57 被阅读0次

    引自: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有三个核心构件:

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

    Java NIO中的几个核心Channel:

    • FileChannel
    • DatagramChannel
    • SocketChannel
    • ServerSocketChannel
    Buffer是一个项部抽象类: Buffer

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

    • ByteBuffer
    • CharBuffer
    • DoubleBuffer
    • FloatBuffer
    • IntBuffer
    • LongBuffer
    • ShortBuffer

    一个线程要管理多个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里的数据有两个注意点:

    • Buffer里的数据是否是全部数据,也就是是否所有数据都已经由Channel中读入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。

    相关文章

      网友评论

          本文标题:Java NIO 简介

          本文链接:https://www.haomeiwen.com/subject/uvbezxtx.html