面试篇-Java输入输出三兄弟大比拼:IO、NIO、AIO对比分析

news/2024/5/8 1:43:04/文章来源:https://blog.csdn.net/citywu123/article/details/130075279

1、Java I/O发展史                

 

Java IO(Input/Output)是Java语言中用于读写数据的API,它提供了一系列类和接口,用于读取和写入各种类型的数据。下面是Java IO发展史的简要介绍:

  1. JDK 1.0(1996年) 最初的Java IO只支持字节流(InputStream、OutputStream)和字符流(Reader、Writer)两种,基于阻塞式IO(BIO)模型。
  2. JDK 1.1(1997年) JDK 1.1引入了NIO(New IO)包,支持了缓存区(Buffer)、通道(Channel)等概念,提供了更高效的IO操作方式,可以实现非阻塞式IO(NIO)模式。
  3. JDK 1.4(2002年) JDK 1.4增加了NIO.2 API,也称为Java NIO with buffers,提供了更   强大的文件处理功能和更高效的IO操作。
  4. JDK 7(2011年) JDK 7引入了NIO.2的改进版——NIO.2 with Completion Ports,也称为AIO(Asynchronous IO),支持异步IO方式,在处理大量并发请求时具有优势。

以下是三者之间的区别:

  1. 阻塞IO(BIO) BIO是Java最初的IO模型,它采用阻塞方式进行数据读写操作。即当一个线程在执行IO操作时,若没有数据可读,则该线程会一直阻塞等待,直到有数据可读或者超时。BIO适合处理连接数比较小且固定的场景,但并发能力不足。
  2. 非阻塞IO(NIO) NIO是Java 1.4引入的新的IO模型,它采用了多路复用器(Selector)机制,通过少量线程同时管理多个通道,实现了单线程同时处理多个请求的效果。NIO具有高并发性、高吞吐量和更高的可靠性,适合处理连接数多且连接时间较短的场景。
  3. 异步IO(AIO) AIO是Java 1.7开始支持的IO模型,它采用事件驱动的方式进行数据读写操作,当数据准备好后,在回调函数中进行处理。与NIO不同,AIO的读写操作是异步的,不需要通过轮询方式去检查数据是否准备好。AIO适合处理连接数多、连接时间长且有较多读写操作的场景。

2、Java IO

2.1 简介

在Java编程中,IO(Input/Output)操作是非常常见的操作,它涉及到文件读写、网络通信等方面。Java提供了各种类来支持这些操作。本文将从IO的基础知识讲起,逐步深入,介绍Java IO的各个方面。

2.2 基础概念

2.2.1 输入流和输出流

在Java中,输入流(InputStream)和输出流(OutputStream)是两个重要的抽象类。输入流表示输入数据的来源,可以是文件、网络连接、管道等;输出流表示输出数据的去向,可以是文件、网络连接、管道等。输入流和输出流的使用方式是相似的,都是通过创建流对象,然后使用相应的方法接口进行读写操作。

2.2.2 字节流和字符流

Java中的IO操作还可以分为字节流和字符流两种。字节流以字节(byte)为单位进行操作,适用于处理二进制数据,例如图像、音频等;而字符流以字符(char)为单位进行操作,适用于处理文本数据,例如文本文件等。Java中,字节流主要由InputStream和OutputStream类以及其子类实现,而字符流主要由Reader和Writer类以及其子类实现。

2.2.3 缓冲流

在进行IO操作时,我们可能需要经常进行读写操作,而频繁的读写可能会导致性能问题。为了解决这个问题,Java提供了缓冲流(Buffered Stream)来提高IO操作的效率。缓冲流可以通过内部缓存区域来减少对底层资源的访问次数,从而提高数据读写的效率。

2.3 Java IO的使用

2.3.1 文件读写

Java中的文件读写是开发中最常见的操作之一。下面是一个读取文件内容并输出的示例:

    try (FileInputStream fis = new FileInputStream("test.txt");InputStreamReader isr = new InputStreamReader(fis);BufferedReader br = new BufferedReader(isr)) {String line;while ((line = br.readLine()) != null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}

在这个示例中,我们使用了FileInputStream、InputStreamReader和BufferedReader等类来完成文件的读取。首先,我们通过FileInputStream类创建了一个输入流对象,并指定了要读取的文件名称;然后通过InputStreamReader将字节流转换为字符流,再通过BufferedReader实现按行读取文本内容。

类似地,在Java中进行文件写操作也非常简单,下面是一个写入文件的示例:

try (FileOutputStream fos = new FileOutputStream("test.txt");OutputStreamWriter osw = new OutputStreamWriter(fos);BufferedWriter bw = new BufferedWriter(osw)) {bw.write("Hello, world!");
} catch (IOException e) {e.printStackTrace();
}

在这个示例中,我们使用了FileOutputStream、OutputStreamWriter和BufferedWriter等类来完成文件的写入。首先,我们通过FileOutputStream类创建了一个输出流对象,并指定了要写入的文件名称;然后通过OutputStreamWriter将字节流转换为字符流,再通过BufferedWriter实现按行写入文本内容。

3、Java NIO

3.1 简介

Java NIO(New IO)是Java SE 1.4引入的一个新的IO API,它提供了比传统IO更高效、更灵活的IO操作。与传统IO相比,Java NIO的优势在于它支持非阻塞IO和选择器(Selector)等特性,能够更好地支持高并发、高吞吐量的应用场景。本文将从NIO的基础知识讲起,逐步深入,介绍Java NIO的各个方面。

3.2 核心概念

 

3.2.1 选择器(Selector)

选择器是Java NIO中的一个重要组件,它可以用于同时监控多个通道的读写事件,并在有事件发生时立即做出响应。选择器可以实现单线程监听多个通道的效果,从而提高系统吞吐量和运行效率。

3.2.2 通道(Channel)

通道是一个用于读写数据的对象,类似于Java IO中的流(Stream)。与流不同的是,通道可以进行非阻塞式的读写操作,并且可以同时进行读写操作。通道分为两种类型:FileChannel和SocketChannel,分别用于文件和网络

通信。

3.2.3 缓冲区(Buffer)

在Java NIO中,所有数据都是通过缓冲区对象进行传输的。缓冲区是一段连续的内存块,可以保存需要读写的数据。缓冲区对象包含了一些状态变量,例如容量(capacity)、限制(limit)、位置(position)等,用于控制数据的读写。

3.3 Java NIO的使用

3.3.1 缓冲区操作

Java NIO中的缓冲区操作主要包括数据读取和数据写入两种操作。下面是一个简单的缓冲区读取示例:

ByteBuffer buffer = ByteBuffer.allocate(1024);
try (FileChannel channel = new FileInputStream("test.txt").getChannel()) {int bytesRead = channel.read(buffer);while (bytesRead != -1) {buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}buffer.clear();bytesRead = channel.read(buffer);}
} catch (IOException e) {e.printStackTrace();
}

在这个示例中,我们使用了FileChannel类和ByteBuffer类来完成文件的读取。首先,我们通过FileInputStream类创建了一个输入流对象,然后通过getChannel()方法获取到对应的通道对象;接着,我们创建了一个容量为1024字节的ByteBuffer对象,并调用read()方法从通道中读取数据,将读取到的数据保存在缓冲区中。读取完成后,我们通过flip()方法将缓冲区切换为读模式,并使用hasRemaining()和get()方法逐个读取数据;最后通过clear()方法清空缓冲区,准备进行下一轮读取。

Java NIO中的缓冲区写操作也非常类似,下面是一个简单的缓冲区写入示例:

ByteBuffer buffer = ByteBuffer.wrap("Hello, world!".getBytes());
try (FileChannel channel = new FileOutputStream("test.txt").getChannel()) {channel.write(buffer);
} catch (IOException e) {e.printStackTrace();
}

在这个示例中,我们使用了FileChannel类和ByteBuffer类来完成文件的写入。首先,我们通过ByteBuffer.wrap()方法将字符串转换为ByteBuffer对象;然后,我们通过FileOutputStream类创建了一个输出流对象,再通过getChannel()方法获取到对应的通道对象;接着,我们调用write()方法将缓冲区中的数据写入通道中,完成文件写入操作。

3.3.2 通道操作

Java NIO中的通道(Channel)是用于进行数据传输的对象。通道可以连接到源或目标节点,用于读取和写入数据。与传统的Java IO不同,NIO中的通道可以实现非阻塞式地读写数据,从而提高了应用程序的性能和并发处理能力。

要使用通道进行读写操作,首先需要打开通道。Java NIO中有多种类型的通道,每种通道都提供了自己的打开方式。例如,要打开一个文件通道,可以通过FileInputStream或FileOutputStream对象获取对应的FileChannel对象,如下所示:

    FileChannel channel = new FileInputStream("file.txt").getChannel();

读取数据 一旦打开了通道,就可以开始读取数据。在NIO中,数据通过缓冲区进行传输。要读取数据,需要将数据存储在缓冲区中,然后从缓冲区中读取数据。以下是一个简单的读取操作示例:

ByteBuffer buffer = ByteBuffer.allocate(1024);
// 从通道中读取数据
int bytesRead = channel.read(buffer);
while (bytesRead != -1) {// 切换为读模式buffer.flip();// 读取缓冲区中的数据while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}// 清空缓冲区buffer.clear();bytesRead = channel.read(buffer);
}

在这个示例中,我们首先创建了一个容量为1024字节的ByteBuffer对象,并使用channel.read()方法从文件通道中读取数据。读取到数据后,我们将ByteBuffer切换为读模式,再使用hasRemaining()和get()方法逐个读取缓冲区中的数据。

写入数据 要写入数据,也需要将数据存储在缓冲区中,然后将缓冲区中的数据写入到通道中。以下是一个简单的写入操作示例:

ByteBuffer buffer = ByteBuffer.wrap("Hello, world!".getBytes());
// 将数据写入通道
channel.write(buffer);

在这个示例中,我们首先使用ByteBuffer.wrap()方法将字符串转换为ByteBuffer对象,在通过channel.write()方法将ByteBuffer中的数据写入到通道中。

4、Java AIO

Java AIO(Asynchronous IO)是一种基于事件和回调的IO模型,相比Java BIO(Blocking IO)和Java NIO(Non-blocking IO),它具有更高的并发性、更高的吞吐量和更高的可靠性。本文将介绍Java AIO的原理、特点和应用。

4.1 Java AIO的原理

Java AIO采用异步IO方式进行数据读写操作,与Java NIO不同,它不需要通过轮询方式去检查数据是否准备好,而是由操作系统完成。当数据准备好后,操作系统会通知应用程序,并在回调函数中进行处理。

AIO使用了三个核心组件:AsynchronousChannel、CompletionHandler和
AsynchronousServerSocketChannel。其中,AsynchronousChannel是读/写数据的通道,CompletionHandler是I/O操作完成时的回调方法,AsynchronousServerSocketChannel是异步服务器端套接字通道,用于监听客户端的连接请求。

当数据准备好后,操作系统将通知应用程序,并在回调函数中执行I/O操作完成时的回调方法。这样就避免了线程阻塞等待I/O操作完成的情况,从而提高了程序的效率和并发处理能力。

4.2 Java AIO的特点

  1. 高并发性:Java AIO采用异步IO方式进行数据读写操作,可以实现高并发处理能力。
  2. 高吞吐量:Java AIO支持异步读写操作,可以同时处理多个请求,从而提高了数据读写的效率和吞吐量。
  3. 高可靠性:由于Java AIO采用异步IO方式进行数据读写操作,可以避免线程阻塞等待I/O操作完成的情况,从而提高程序的可靠性。
  4. 简单易用:Java AIO提供了简单易用的API,不需要编写复杂的代码就可以实现异步IO操作。

4.3 Java AIO的应用

Java AIO适用于需要大量并发连接,但每个连接却很少有数据交互的场景,例如基于消息的应用程序、远程过程调用(RPC)等。在这些应用场景中,AIO可以大幅度提高程序的性能和并发处理能力,从而满足用户对高吞吐量和低延迟的要求。

另外,Java AIO也可以用于开发高性能的网络服务器,例如聊天室服务器、在线游戏服务器等。由于AIO支持异步读取输入流和输出流,因此可以同时处理多个客户端请求,有效地提高了服务器的并发处理能力。

4.4 总结

Java AIO作为一种高性能、高并发的IO模型,具备很多优点,但也存在着一些缺点,如对小负载的连接,AIO的开销可能会导致性能下降。因此,在实际应用中,需要权衡各种因素,根据实际需求进行评估和选择。

5、相关面试题

1、什么是Java IO和NIO?
Java IO(Input/Output)是Java中传统的输入输出操作,使用字节流和字符流进行数据传输。
Java NIO(New Input/Output)是Java 1.4引入的新的输入输出API,它更加高效地处理数据。
2、什么是阻塞和非阻塞IO?
阻塞IO(Blocking IO)在进行IO操作时会一直等待,直到IO完成,期间无法进行其他操作。
非阻塞IO(Non-blocking IO)在进行IO操作时不会一直等待,而是立即返回结果,如果IO还没有完全完成,则可以继续做其他事情。
3、什么是缓冲区?有哪些类型的缓冲区?
缓冲区是一个用于存储数据的数组,在进行IO操作时需要通过缓冲区来进行读写数据。
Java的缓冲区分为字节缓冲区(ByteBuffer、CharBuffer、ShortBuffer等)和直接缓冲区(DirectByteBuffer、DirectCharBuffer、DirectShortBuffer等)。
4、什么是通道(Channel)?
通道是NIO中用于进行数据传输的对象,它可以连接到源或目标节点,用于读取和写入数据。
5、什么是选择器(Selector)?
选择器是NIO中的一个对象,它可以通过轮询注册在其上的通道来检查它们是否有事件发生(如可读、可写等),从而避免了阻塞式IO中需要等待IO完成的问题。
6、Java IO和NIO之间有什么区别?
Java IO基于流的方式进行数据传输,而NIO基于缓冲区和通道进行数据传输。
Java IO是阻塞式的,而NIO可以采用阻塞或非阻塞模式。
Java IO对线程使用较多,每个IO操作都需要创建一个线程,而NIO可以使用单个线程处理多个IO操作。
7、什么是文件通道(FileChannel)?
文件通道是NIO中用于读取和写入文件的通道,它支持随机访问和内存映射文件等高级功能。
8、Java IO和NIO哪个更快?
在大量小数据量的情况下,Java IO可能更快,因为它可以通过缓冲区一次性读取所有数据。
在大量大块数据的情况下,NIO可能更快,因为它可以使用零拷贝技术直接将数据从磁盘读入内存,减少了数据复制的开销。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_96335.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在大厂做好架构演进?

1 架构演进的定义 1.1 定义 通过设计新的系统架构(4R),来应对业务和技术的发展变化。 1.2 关键点 新架构新的复杂度 1.3 目的 应对业务和技术的发展变化后带来新的复杂度。 案例 淘宝去IOE,是因为业务发展大了后,IOE的成本和可控性难…

MySQL SQL优化 【建议熟读并背诵】

插入数据 批量插入数据 insert into tb_test values(1,Tom),(2,Cat),(3,Jerry);手动控制事务 start transaction; insert into tb_test values(1,Tom),(2,Cat),(3,Jerry); insert into tb_test values(4,Tom),(5,Cat),(6,Jerry); insert into tb_test values(7,Tom),(8,Cat…

事实胜于雄辩,苹果MacOs能不能玩儿机器/深度(ml/dl)学习(Python3.10/Tensorflow2)

坊间有传MacOs系统不适合机器(ml)学习和深度(dl)学习,这是板上钉钉的刻板印象,就好像有人说女生不适合编程一样的离谱。现而今,无论是Pytorch框架的MPS模式,还是最新的Tensorflow2框架,都已经可以在M1/M2芯片的Mac系统…

【计算机网络-应用层】域名系统 DNS、文件传输协议 FTP、电子邮件

文章目录1 域名系统 DNS1.1 域名结构1.2 域名服务器1.2.1 根域名服务器1.2.2 顶级域名服务器1.2.3 权限域名服务器1.2.4 本地域名服务器1.3 域名解析过程1.3.1 递归查询1.3.2 递归与迭代相结合查询1.3.3 本地域名服务器的高速缓存2 文件传输协议 FTP2.1 主动模式(建…

CSDN,感谢遇见【我的一周年创作纪念日】

机缘 第一次遇见CSDN已经是7年前的事了,那时的我还是一名初二的学生,由于沉迷于玩具战争这款游戏(很遗憾这款游戏已经停服),里面有许多大佬利用各种手段去开挂,所以我意外的接触到了浏览器抓包等计算机技术…

Kafka消费者组和分区再均衡

应用程序使用KafkaConsumer向Kafka订阅主题,并从订阅的Topic上接收消息。 要想知道如何从Kafka读取消息,需要先了解消费者和消费者组的概念。 1、消费者和消费者组 原因:假设我们有一个应用程序需要从一个Kafka Topic中读取消息并验证&…

C++实现前缀树

文章目录1. 什么是前缀树2. 前缀树的实现2.1 前缀树的基本结构2.2 插入2.3 word出现了几次2.3 word作为前缀出现几次2.4 删除1. 什么是前缀树 假设这里有一个字符串数组,和一个树的根结点: 这个结点的pass意思是:有几个字符通过了这个结点。…

(学习日记)2023.4.10

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…

Jetpack Compose之对话框和进度条

概述 对话框和进度条其实并无多大联系,放在一起写是因为两者的内容都不多,所以凑到一起,对话框是我们平时开发使用得比较多的组件,像隐私授权,用户点击删除时给用户提示这是一个危险操作等,进度条的使用频…

npm与node版本不匹配问题解决思路

1.报错 npm WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: ‘electron-packager17.1.1’, npm WARN EBADENGINE required: { node: ‘> 14.17.5’ }, npm WARN EBADENGINE current: { node: ‘v12.22.9’, npm: ‘8.5.1’ } npm WARN EBADENGINE } np…

3款免费好用的电脑录屏工具

案例:电脑录屏工具哪款免费又好用? “我想要挑选一款适合自己的好用的电脑录屏软件,但是我尝试了很多款录屏软件结果都不尽人意。免费版的软件功能少,录制效果差,想要高级功能需要付费解锁。想问问大家有没有免费好用…

Mybatis操作Oracle中的Clob和Blob字段

文章目录Mybatis操作Oracle中的Clob和Blob字段1. Oracle中创建测试的表结构&#xff1a;Byte_Array_Test2. Mybatis配置MapperXml&#xff0c;用Map<String, Object>接受Clob和Blob的数据&#xff0c;如下图&#xff1a;3. 代码中获取Clob和Blob的值3-1 接收Blob和Clob数…

每日做题总结——day01

目录 选择题 for循环 指针数组 位段 getchar 大小端存储 进制与格式控制符 位运算 数组指针 二维数组的存储 计算二进制中1的个数 斐波那契数列求递归次数 编程题 删除公共字符 排序子序列 倒置字符串 选择题 for循环 解析&#xff1a;该题主要看for…

el-form, 时间选择器,不管选择什么时间范围,值一直是当月一号

yyyy-MM-DD 修改为 yyyy-MM-dd 就好了&#xff0c;bug千奇百怪 修改前 修改后

极致低延迟收集器ZGC探索——亚毫秒级,常数级暂停O(1)原理

ZGC 收集器 ZGC收集器&#xff08;Z Garbage Collector&#xff09;是由Oracle公司为HotSpot JDK研发的&#xff0c;最新一代垃圾收集器。有说法使用这个名目标是取代之前的大部分垃圾收集器&#xff0c;所以才叫ZGC&#xff0c;表示极致的Extremely&#xff0c;或者最后的&am…

RHCE——shell脚本练习

一.实验要求 1、判断web服务是否运行&#xff08;1、查看进程的方式判断该程序是否运行&#xff0c;2、通过查看端口的方式判断该程序是否运行&#xff09;&#xff0c;如果没有运行&#xff0c;则启动该服务并配置防火墙规则。 ​2、使用curl命令访问第二题的web服务&#xff…

Vulnhub靶场DC-1练习

目录0x00 准备0x01 主机信息收集0x02 站点信息收集0x03 漏洞查找与利用0x00 准备 下载链接&#xff1a;https://download.vulnhub.com/dc/DC-1.zip 介绍&#xff1a;There are five flags in total, but the ultimate goal is to find and read the flag in root’s home dir…

Linux宝塔安装msyql服务,默认密码,允许远程登录问题解决

一、首先我在宝塔安装mysql服务是5.7 1.1MySQL数据库5.6之前&#xff08;不包括&#xff09;默认密码为空&#xff0c;用户不用输入密码&#xff0c;直接回车登陆 mysql -uroot -p password:(空) 1.2.MySQL数据库5.6之后&#xff08;包括&#xff09;默认密码是MySQL数据库随机…

Springboot基础学习之(十四):修改使用数据库中的数据源,修改为Druid:通过Druid实现后台监控

文章的顺序&#xff0c;是本人学习Springboot这个框架的先后顺序 这一篇文章讲解的是如何整合数据库中的数据源 Java程序很大一部分要操作数据库&#xff0c;为了提高性能操作数据库的时候&#xff0c;又不得不使用数据库连接池。 Druid 是阿里巴巴开源平台上一个数据库连接池实…

web综合

一&#xff0c;基于域名访问www.openlab.com 在文件当中写入IP与域名的映射关系 在windows中写入 也可以在客户端的/etc/hosts下写入映射关系 创建目录 [rootserver ~]# mkdir -pv /www/openlab 将所需要的内容写入对应目录当中 [rootserver ~]# echo welcome to openlab ! &…