【Java NIO】那NIO为什么速度快?

Java IO在工作中其实不常用到,更别提NIO了。但NIO却是高效操作I/O流的必备技能,如顶级开源项目Kafka、Netty、RocketMQ等都采用了NIO技术,NIO也是大多数面试官必考的体系知识。虽然骨头有点难啃,但还是要慢慢消耗知识、学以致用哈~

🌱以贴近现实的【面试官面试】形式涵盖大部分Java程序员需要掌握的后端知识、面试问题,系列博客收录在我开源的JavaGetOffer中,会一直完善下去,希望收到大家的 ⭐️ Star ⭐️支持,这是我创作的最大动力: github.com/hdgaadd/Jav...

1. Java NIO

面试官:了解过NIO吗?

了解的面试官。NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。

NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。

程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。

1.1 通道和缓冲器

面试官:那NIO为什么速度快?

是这样的,NIO提供了通道和缓冲器这两个核心对象。

(1)管道Channel

与传统的IO流只能只读或只写的单向流 不同,NIO通道是双向的,也就是说读写操作可以同时进行,使得数据的处理效率也更高。

(2)缓冲器Buffer

传统的输入/输出流一次只处理一个字节,而每一次字节读取都是一次系统调用,涉及到用户空间和内核空间之间的上下文切换,通常来说效率不高。

NIO采用内存映射文件方式来处理输入/输出,Channel通过map()方法把一块数据 映射到内存中。程序通过Buffer进行数据交互,减少了与原始数据源的直接访问。NIO面向块的处理方式使得效率更高。

1.2 非阻塞IO模型

面试官:还有吗?

有的。

传统的输入/输出流是同步阻塞IO模型,如果数据源没有数据了,此时程序将进行阻塞。

NIO是I/O多路复用模型,线程可以询问通道有没可用的数据,而不需要在没有数据时阻塞掉线程。

1.3 字符流处理字符?

面试官:你刚刚说输入/输出流是处理字节?字符流不是处理字符吗?

不是的。所有数据包括文本数据最终都是以字节形式存储的,因为计算机底层只能理解二进制数据。

字符最终也是要转换成字节形式,之所以可以在文本文件看到字符,是因为系统将底层的二进制序列转换成了字符。

2. Channel和Buffer使用

2.1 Buffer

面试官:你具体介绍下Buffer?

好的,Buffer里有3个关键变量

  1. capcity:表示缓冲器Buffer的最大数据容量。
  2. position:用来指出下一个可以读出/写入Buffer的索引位置,也就是记录指针的作用。
  3. limit:用来表示在Buffer里第一个不能被读出/写入的索引位置。

另外Buffer还提供了getput方法来供我们操作数据,而使用get/put后,position的指针位置也会随之移动。

java 复制代码
public abstract byte get();

public abstract ByteBuffer put(byte b);

2.2 Channel

面试官:Channel呢?

Channel有常见的3个方法,map()、read()和write()。

java 复制代码
// 将通道文件的区域直接映射到字节缓冲区中
public abstract MappedByteBuffer map(MapMode mode, long position, long size)

// 从此Channel通道读取字节序列到给定缓冲区dst
public abstract int read(ByteBuffer dst)
    
// 将给定缓冲区中src的字节序列写入此Channel通道
public abstract int write(ByteBuffer src)

以下是Channel的简单使用代码。

java 复制代码
public class TestFileChannel {
    public static void main(String[] args) {
        File f = new File("D:\\JavaGetOffer\\TestFileChannel.java");
        try {
            FileChannel inChannel = new FileInputStream(f).getChannel();
            FileChannel outChannel = new FileOutputStream("a.txt").getChannel();
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());

            outChannel.write(buffer);
            buffer.clear();
            CharBuffer charBuffer = StandardCharsets.UTF_8.newDecoder().decode(buffer);
            System.out.println(charBuffer);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

3. NIO零拷贝

面试官:知道NIO零拷贝吗?

是这样的,在NIO零拷贝出现之前,一个I/O操作会将同一份数据进行多次拷贝。可以看下图,一次I/O操作对数据进行了四次复制,同时来伴随两次内核态和用户态的上下文切换,众所周知上下文切换是很耗费性能的操作。

而零拷贝技术改善了上述的问题。可以对比下图,零拷贝技术减少 了对一份数据的拷贝次数,不再需要将数据在内核态和用户态之间进行拷贝,也意味不再进行上下文切换,让数据传输变得更加高效。

未完待续。。。

好了,今天的分享就先到这,我们下期《Java IO系列》继续。

创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️

相关推荐
程序媛-徐师姐8 分钟前
Java 基于SpringBoot+vue框架的老年医疗保健网站
java·vue.js·spring boot·老年医疗保健·老年 医疗保健
yngsqq9 分钟前
c#使用高版本8.0步骤
java·前端·c#
尘浮生19 分钟前
Java项目实战II基于微信小程序的校运会管理系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
小白不太白95023 分钟前
设计模式之 模板方法模式
java·设计模式·模板方法模式
Tech Synapse25 分钟前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
.生产的驴26 分钟前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
xoxo-Rachel31 分钟前
(超级详细!!!)解决“com.mysql.jdbc.Driver is deprecated”警告:详解与优化
java·数据库·mysql
乌啼霜满天24933 分钟前
JDBC编程---Java
java·开发语言·sql
微信-since8119241 分钟前
[ruby on rails] 安装docker
后端·docker·ruby on rails