【Java基础】NIO 初步了解

系统工
• 阅读 798

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 的对比:

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

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

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

3、选择器
允许一个线程管理多个输入通道。
【Java基础】NIO 初步了解

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

处理数据的流程:
阻塞 IO
【Java基础】NIO 初步了解

NIO
【Java基础】NIO 初步了解

二、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 数据如下所示,参考下面的可以帮你更好的理解,几个操作都做了什么事情。
【Java基础】NIO 初步了解

当然,也可以直接看源码,很简洁易懂:(如 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 详解(一)

点赞
收藏
评论区
推荐文章
5种I/O模型
阻塞I/O(blockingI/O)非阻塞I/O(nonblockingI/O)同步I/O(synchronousI/O)or多路复用I/O(multiplexingI/O)异步I/O(asynchronousI/O)信号驱动I/O(signaldrivenI/O)1.阻塞I/O:第1阶段:内核准备数据,进程阻塞第2阶段:拷贝数据(
Wesley13 Wesley13
4年前
java的NIO
java的NIO        java的NIO主要有3个特性Channel、buffer、selector来保证I/O高可复用性,其中最重要的是buffer和selector操作。详细教材查看jakobjenkov教材:http://tutorials.jenkov.com/javanio/index.html(https://www
Wesley13 Wesley13
4年前
javaIO2
NIO新的输入/输出(NIO)库是在JDK1.4中引入的,弥补了原来的I/O的不足,提供了高速的、面向块的I/O。1.1流与块I/O与NIO最重要的区别是数据打包和传输的方式,I/O以流的方式处理数据,而NIO以块的方式处理数据。面向流的I/O一次处理一个字节数据:一个输入流产生一个字
Wesley13 Wesley13
4年前
NIO入门
1、I/O输入输出,所有的IO都被视作是单个字节的移动,通过stream对象一次移动一个字节。流IO负责把对象转换为字节,然后再转换为对象。NIO提供了二套NIO,一套是针对标准输入输出NIO,另一套是网络编程NIO2、流与块的比较NIO和IO最大的区别是数据打包和传输方式,IO是以流的方式来处理数据,而NIO是以块的方式处理数据。面向块的IO
Stella981 Stella981
4年前
NIO 看破也说破(四)—— Java的NIO
Java的NIO有selector,系统内核也提供了多种非阻塞IO模型,Java社区也出现了像netty这种优秀的NIO框架。Java的NIO与内核的阻塞模型到底什么关系,为什么Java有NIO的API还出现了netty这种框架,网上说的reactor到底是什么?本文通过分析代码,带你一步步搞清楚Java的NIO和系统函数之间的关系,以及Java
Wesley13 Wesley13
4年前
Java NIO和IO的区别
IO               NIO面向流           面向缓冲阻塞IO           非阻塞IO无               选择器面向流与面向缓冲JavaNIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。JavaIO面向流意味着每次从流中
Stella981 Stella981
4年前
Netty(二)
一、先讲下NIO编程。NIO(NonblockI/O),亦叫做非阻塞I/O与Socket类和ServerSocket类相对应,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。1 缓冲区Buffer这里首先介绍缓冲区的概念,NIO和原I/O的一个重要区别就是NIO库中,所有数据都是用缓
Wesley13 Wesley13
4年前
Java NIO学习笔记
JavaNIO是什么JavaNIO(NewIO)是从Java1.4版本开始引入的一个新的IOAPI,可以替代标准的JavaIOAPI。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。JavaNIO与IO
Wesley13 Wesley13
4年前
JAVA NIO入门(一)
一、JAVANIO概念  JAVANIO是从JDK1.4就开始有的,之前只用过IO流,其实NIO和IO一样都是可以用来读取或者写入文件,只不过原来的IO是面向流进行操作的,而NIO是面向缓冲区进行操作二、通过一个小例子初步了解下NIO如何进行文件读写 !(https://oscimg.oschina.net/oscnet/
Wesley13 Wesley13
4年前
Java Nio 线程
JavaNIO(NewIO)是从Java1.4版本开始引入的 一个新的IOAPI,可以替代标准的JavaIOAPI。 NIO与原来的IO有同样的作用和目的,但是使用 的方式完全不同,NIO支持面向缓冲区的、基于 通道的IO操作。NIO将以更加高效的方式进行文 件的读写操作JavaNIO与IO的主要区别
Wesley13 Wesley13
4年前
Java NIO
简介引入NIO的原因1.因为BIO都是阻塞的IO,为了使Java能支持非阻塞I/O,JDK引入了NIO,可以将NIO理解成是NonblockI/O.(也有书说是newIO)2.BIO编程中,每当有一个新的客户端请求过来时,服务器端必须创建一个新的线程处理新接入的客户端链路,一个线程只能处理一个客户端连接,在并发量