【Java基础】NIO 初步了解

NIO(Non-blocking I/O,在 Java 领域,也称为 New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础。那和普通 IO 有什么区别呢?

一、概述

NIO 是从 Java 1.4 版本开始引入的一个新的 IO API,NIO 支持面向缓冲区的、基于通道的 IO 操作。
原来的 IO 是阻塞式 IO,与 NIO 的对比:

IO NIO
面向流 面向缓冲
阻塞 IO 非阻塞 IO
选择器

1、面向流和面向缓冲
面向流是每次从流中读取一个或多个字节,直到读取完。读过了就过了。
面向缓冲是把数据先放到缓冲区中,需要读取的时候从缓冲区拿,缓冲区数据读取后还在,还能通过指针移动读取缓冲区中不同的数据。

2、阻塞/非阻塞
阻塞就是不读写数据的时候也要占着线程,不能干别的。非阻塞是不读写的时候该线程可以干别的事情。

3、选择器
允许一个线程管理多个输入通道。
image.png

使用场景:
NIO:需要管理同时打开的多个连接(如聊天服务器),连接每次仅发送少量数据。
IO:少量连接,每次发送大量数据

处理数据的流程:
阻塞 IO
image.png

NIO
image.png

二、NIO 基础

BufferChannel是标准NIO中的核心对象。

  • Channel 是对原IO中流的模拟,任何来源和目的数据都必须通过一个Channel对象
  • Buffer 实质上是一个容器对象,发给 Channel 的所有对象都必须先放到 Buffer 中;同样的,从 Channel 中读取的任何数据都要读到 Buffer 中。

一)关于 Buffer

Buffer 包含一些要写入或读出的数据。在 NIO 中,所有的数据都是用 Buffer 处理的,它是 NIO 读写数据的中转池。Buffer 实质上是一个数组,提供对数据结构化访问的功能。
使用 Buffer 读写数据一般有以下四个步骤:

  1. 写入数据到 Buffer;
  2. 调用 flip() 方法,从写模式转换为读模式;
  3. 从 Buffer 中读取数据;
  4. 调用 clear() 方法(清空);或者 compact() 方法(清除已读数据)。

二)关于 Channel

可以通过 Channel 读取和写入数据。可以把它看做 IO 中的流。但是它和流相比还有一些不同。

  • Channel 是双向的,既可以读又可以写,而流是单向的
  • Channel 可以进行异步的读写
  • 对 Channel 的读写必须通过 buffer 对象

三、案例 demo

下面通过一个案例讲解 NIO 的操作过程。
将从一个文件中读取数据,写入到另一个文件中,代码如下

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class CopyFileUseNIO {
    public static void main(String[] args) throws IOException {
        String src = "/xxxx/LICENSE.txt";
        String dst = "/xxxx/LICENSE-COPY.txt";

        FileInputStream fi = new FileInputStream(src);
        FileOutputStream fo = new FileOutputStream(dst);

        //获得传输通道channel
        FileChannel inChannel = fi.getChannel();
        FileChannel outChannel = fo.getChannel();

        //获得容器buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while (true) {
            //判断是否读完文件
            int eof = inChannel.read(buffer); // #1
            if (eof == -1) {
                break;
            }
            //重设一下buffer的position=0,limit=position
            buffer.flip();        // #2
            //开始写
            outChannel.write(buffer);  // #3
            //写完要重置buffer,重设position=0,limit=capacity
            buffer.clear();  // #4
        }

        inChannel.close();
        outChannel.close();
        fi.close();
        fo.close();
    }
}

关注上面有注释的 #1 ~ #4 四个位置。
四个位置代码执行后 buffer 数据如下所示,参考下面的可以帮你更好的理解,几个操作都做了什么事情。
image.png

当然,也可以直接看源码,很简洁易懂:(如 clear 的操作逻辑)

    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

四、总结

本节对 NIO 进行了简要介绍。与原 IO 进行了对比,对 NIO 的读写流程进行了介绍,讲解了 NIO 重要的概念 buffer 和 channel。所有的数据必须经过 buffer 处理,channel 仅是连接的管道,不能直接从 channel 中获取数据。
NIO 有非阻塞的特性,不会在读写未完毕时持续阻塞线程,当未在读写时,线程可以处理别的事情。
最后提供了读写数据的 demo 帮助理解。


参考文章:
Java NIO浅析
Java常见面试题汇总-----------Java基础(NIO与IO的区别)
Java NIO 详解(一)

你可能感兴趣的:(javanio)