Java 中的NIO、BIO和AIO详细总结

Java IO 与 BIO、NIO

        IO,常写作 I/O,是 Input/Output 的简称,即输入/输出。通常指数据在内部存储器(内存)和外部存储器(硬盘、优盘等)或其他周边设备之间的输入和输出。

        输入/输出是信息处理系统与外部世界之间的通信,输入是系统接收的信号或数据,输出则是从其发送的信号或数据。

        在 Java 中,提供了一系列 API,可以供开发者来读写外部数据或文件。我们称这些 API 为 Java IO。

        BIO 全称 Block-IO 是一种同步且阻塞的通信模式。是一个比较传统的通信方式,模式简单,使用方便。但并发处理能力低,通信耗时,依赖网速。

        Java NIO,全程 Non-Block IO ,是 Java SE 1.4 版以后,针对网络传输效能优化的新功能。是一种非阻塞同步的通信模式。NIO 与原来的 I/O 有同样的作用和目的, 他们之间最重要的区别是数据打包和传输的方式。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。

        面向流的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。

        面向块的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。

        Java AIO,全称 Asynchronous IO,是异步非阻塞的 IO。是一种非阻塞异步的通信模式。

三种 IO 的区别

BIO (Blocking I/O):同步阻塞 I/O 模式。

NIO (New I/O):同步非阻塞模式。

AIO (Asynchronous I/O):异步非阻塞 I/O 模型。

同步阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,并坐在水壶面前一直等着水烧开。

同步非阻塞模式:这种模式下,我们的工作模式是先来到厨房,开始烧水,但是我们不一直坐在水壶前面等,而是回到客厅看电视,然后每隔几分钟到厨房看一下水有没有烧开。

异步非阻塞 I/O 模型:这种模式下,我们的工作模式是先来到厨房,开始烧水,我们不一直坐在水壶前面等,也不隔一段时间去看一下,而是在客厅看电视,水壶上面有个开关,水烧开之后他会通知我。

阻塞 VS 非阻塞:人是否坐在水壶前面一直等。

同步 VS 异步:水壶是不是在水烧开之后主动通知人。

使用方式

使用 BIO 实现文件的读取和写入

public class BioFileDemo {public static void main(String[] args) {BioFileDemo demo = new BioFileDemo();demo.writeFile();demo.readFile();}// 使用 BIO 写入文件public void writeFile() {String filename = "logs/itwanger/paicoding.txt";try {FileWriter fileWriter = new FileWriter(filename);BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);bufferedWriter.write("学编程就上技术派");bufferedWriter.newLine();System.out.println("写入完成");bufferedWriter.close();fileWriter.close();} catch (IOException e) {e.printStackTrace();}}// 使用 BIO 读取文件public void readFile() {String filename = "logs/itwanger/paicoding.txt";try {FileReader fileReader = new FileReader(filename);BufferedReader bufferedReader = new BufferedReader(fileReader);String line;while ((line = bufferedReader.readLine()) != null) {System.out.println("读取的内容: " + line);}bufferedReader.close();fileReader.close();} catch (IOException e) {e.printStackTrace();}}
}

        这个示例展示了如何使用 Java 中的传统阻塞 I/O(BIO)对文件进行读写操作。在 writeFile() 方法中,我们首先创建一个 FileWriter 对象,并使用 BufferedWriter 进行缓冲写入。接着,使用 bufferedWriter.write() 方法将字符串写入文件,然后调用 bufferedWriter.newLine() 方法添加换行符。最后,关闭 BufferedWriter 和 FileWriter。在 readFile() 方法中,我们创建一个 FileReader 对象,并使用 BufferedReader 进行缓冲读取。然后通过调用 bufferedReader.readLine() 方法循环读取文件内容,直到返回 null 表示读取完毕。最后,关闭 BufferedReader 和 FileReader。

NIO 的使用

public class NioFileDemo {public static void main(String[] args) {NioFileDemo demo = new NioFileDemo();demo.writeFile();demo.readFile();}// 使用 NIO 写入文件public void writeFile() {Path path = Paths.get("logs/itwanger/paicoding.txt");try {FileChannel fileChannel = FileChannel.open(path, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE));ByteBuffer buffer = StandardCharsets.UTF_8.encode("学编程就上技术派");fileChannel.write(buffer);System.out.println("写入完成");fileChannel.close();} catch (IOException e) {e.printStackTrace();}}// 使用 NIO 读取文件public void readFile() {Path path = Paths.get("logs/itwanger/paicoding.txt");try {FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = fileChannel.read(buffer);while (bytesRead != -1) {buffer.flip();System.out.println("读取的内容: " + StandardCharsets.UTF_8.decode(buffer));buffer.clear();bytesRead = fileChannel.read(buffer);}fileChannel.close();} catch (IOException e) {e.printStackTrace();}}
}

        这个示例演示了如何使用 NIO 的FileChannel 对文件进行读写操作。在 writeFile() 方法中,我们首先打开文件通道并指定创建和写入选项。接着,将要写入的字符串转换为 ByteBuffer,然后使用 fileChannel.write() 方法将其写入文件。在 readFile() 方法中,我们打开文件通道并指定读取选项,然后创建一个 ByteBuffer 用于存储读取到的数据。使用 fileChannel.read() 方法循环读取文件内容,直到返回 -1 表示读取完毕。在循环中,我们翻转缓冲区,将其解码为字符串并打印,然后清空缓冲区以进行下一次读取。最后,关闭文件通道。

使用 AIO 实现文件的读取和写入

public class AioDemo {public static void main(String[] args) {AioDemo demo = new AioDemo();demo.writeFile();demo.readFile();}// 使用 AsynchronousFileChannel 写入文件public void writeFile() {// 使用 Paths.get() 获取文件路径Path path = Paths.get("logs/itwanger/paicoding.txt");try {// 用 AsynchronousFileChannel.open() 打开文件通道,指定写入和创建文件的选项。AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);// 将要写入的字符串("学编程就上技术派")转换为 ByteBuffer。ByteBuffer buffer = StandardCharsets.UTF_8.encode("学编程就上技术派");// 调用 fileChannel.write() 方法将 ByteBuffer 中的内容写入文件。这是一个异步操作,因此需要使用 Future 对象等待写入操作完成。Future<Integer> result = fileChannel.write(buffer, 0);// 等待写操作完成result.get();System.out.println("写入完成");fileChannel.close();} catch (IOException | InterruptedException | java.util.concurrent.ExecutionException e) {e.printStackTrace();}}// 使用 AsynchronousFileChannel 读取文件public void readFile() {Path path = Paths.get("logs/itwanger/paicoding.txt");try {// 指定读取文件的选项。AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);// 创建一个 ByteBuffer,用于存储从文件中读取的数据。ByteBuffer buffer = ByteBuffer.allocate(1024);// 调用 fileChannel.read() 方法从文件中异步读取数据。该方法接受一个 CompletionHandler 对象,用于处理异步操作完成后的回调。fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {// 在 CompletionHandler 的 completed() 方法中,翻转 ByteBuffer(attachment.flip()),然后使用 Charset.forName("UTF-8").decode() 将其解码为字符串并打印。最后,清空缓冲区并关闭文件通道。attachment.flip();System.out.println("读取的内容: " + StandardCharsets.UTF_8.decode(attachment));attachment.clear();try {fileChannel.close();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {// 如果异步读取操作失败,CompletionHandler 的 failed() 方法将被调用,打印错误信息。System.out.println("读取失败");exc.printStackTrace();}});// 等待异步操作完成Thread.sleep(1000);} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}

        这段代码展示了一个名为 AioDemo 的类,包含两个方法:writeFile() 和 readFile()。这两个方法分别使用 AsynchronousFileChannel 对文件进行异步写入和读取操作。代码的具体含义我都加到注释当中了,注意查看。

小结

BIO(Blocking I/O):采用阻塞式 I/O 模型,线程在执行 I/O 操作时被阻塞,无法处理其他任务,适用于连接数较少且稳定的场景。

NIO(New I/O 或 Non-blocking I/O):使用非阻塞 I/O 模型,线程在等待 I/O 时可执行其他任务,通过 Selector 监控多个 Channel 上的事件,提高性能和可伸缩性,适用于高并发场景。

AIO(Asynchronous I/O):采用异步 I/O 模型,线程发起 I/O 请求后立即返回,当 I/O 操作完成时通过回调函数通知线程,进一步提高了并发处理能力,适用于高吞吐量场景。

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

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

相关文章

数据结构之栈的实现与排序详解与示例(C, C#, C++)

文章目录 栈的基本操作栈的排序总结 栈是一种后进先出&#xff08;Last In First Out, LIFO&#xff09;的数据结构。在栈中&#xff0c;元素的插入和删除操作都发生在同一端&#xff0c;即栈顶。本文将详细介绍如何实现栈的排序&#xff0c;并提供C, C#, C三种语言的示例。 栈…

【46 Pandas+Pyecharts | 当当网畅销图书榜单数据分析可视化】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 去除重复数据2.4 书名处理2.5 提取年份 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 作者图书数量分布3.2 图书出版年份…

JVM--垃圾收集算法

1.分代收集理论 垃圾收集算法可以划分为“引用计数式垃圾收集”&#xff08;ReferenceCounting GC&#xff09;和“追踪式垃圾收集”&#xff08;Tracing GC&#xff09;两大类&#xff0c;本次仅仅讨论踪式垃圾收集 谈到垃圾收集 &#xff0c;首先先了解分代的收集理论&#x…

Nuxt.js头部魔法:轻松自定义页面元信息,提升用户体验

title: Nuxt.js头部魔法&#xff1a;轻松自定义页面元信息&#xff0c;提升用户体验 date: 2024/7/16 updated: 2024/7/16 author: cmdragon excerpt: 摘要&#xff1a;“Nuxt.js头部魔法&#xff1a;轻松自定义页面元信息&#xff0c;提升用户体验”介绍如何使用useHead函数…

智能合约中授权与转账的分离可行性分析

概览 本文档旨在探讨智能合约中授权与转账操作为何通常被设计为分离的步骤&#xff0c;以及在授权与转账之后&#xff0c;是否能够立即进行连续的代币转移。我们将从安全性、效率、灵活性和操作流程的角度分析这些问题。 授权与转账操作的分离 目标与原因 安全性增强&#…

mybatis的xml中,where标签不自动删除多余的and之类的问题

遇到了这个莫名其妙的问题&#xff0c;起初是很疑惑的&#xff0c;where标签好像失灵了一般不会自动删除掉 多余的and 看了眼sql语句&#xff0c;发现还是有and没被删除。 后来重新写了遍后发现又没事了。真的是神人。 然后就研究了好一会&#xff0c;发现&#xff01;&#…

什么是Go中的泛型与接口,它们都有哪些优缺点?

Golang 中的泛型与空接口 泛型简介 泛型允许在编写能够处理任意类型的代码&#xff0c;而无需在每次使用不同类型时都重新编写代码。泛型的核心是类型参数&#xff0c;这些参数在函数、结构体或接口中定义&#xff0c;并在使用时进行具体化。 泛型函数 使用泛型函数时&…

Uniapp中image的@load不触发问题

load 事件不触发的常见情况有以下几种: 图片缓存命中 当图片从浏览器缓存中加载时,load 事件通常不会被触发。这是因为浏览器认为这个图片已经成功加载过了,所以不会再次触发 load 事件。 图片地址未发生变化 如果 image 组件的 src 属性值没有发生变化,即使图片是从网络上加载…

C++——关于new和delete

在C语言中我们想要动态管理内存空间&#xff0c;需要使用到malloc/calloc/realloc/free这些函数&#xff0c;在 C中有新的管理方式&#xff0c;那就是new和delete。new和delete是C新定义的操作符&#xff0c;专门用于管理堆上的内存空间。 new和delete在编译时&#xff0c;编译…

Linux C++ 055-设计模式之状态模式

Linux C 055-设计模式之状态模式 本节关键字&#xff1a;Linux、C、设计模式、状态模式 相关库函数&#xff1a; 概念 状态模式&#xff08;State Pattern&#xff09;是设计模式的一种&#xff0c;属于行为模式。允许一个对象在其内部状态改变时改变它的行为。对象看起来似…

Rust RefCell<T> 和内部可变性模式

内部可变性&#xff08;Interior mutability&#xff09;是 Rust 中的一个设计模式&#xff0c;它允许你即使在有不可变引用时也可以改变数据&#xff0c;这通常是借用规则所不允许的。为了改变数据&#xff0c;该模式在数据结构中使用 unsafe 代码来模糊 Rust 通常的可变性和借…

移动UI:具备什么特征,可以被认定为科技风格。

移动UI设计在科技风格上通常具备以下特征&#xff1a; 1. 清晰简洁的排版&#xff1a; 科技风格的移动UI通常采用清晰简洁的排版&#xff0c;注重信息的层次感和结构化&#xff0c;以便用户能够快速、直观地获取所需信息。 2. 几何形状和线条&#xff1a; 科技风格的移动UI常…

【算法】代码随想录之哈希表(更新中)

文章目录 前言 一、有效的字母异位词&#xff08;LeetCode--242&#xff09; 二、两个数组的交集&#xff08;LeetCode--349&#xff09; 前言 跟随代码随想录&#xff0c;学习哈希表相关的算法题目&#xff0c;记录学习过程中的tips。 一、有效的字母异位词&#xff08;Le…

HashMap的扩容原理

1.7版本 1.先生成新数组 2.遍历老数组中的每个位置上的链表上的每个元素 3.取每个元素的key&#xff0c;并基于新数组长度&#xff0c;计算出每个元素在新数组中的下标 4.将元素添加到新数组中去 5.所有元素转移完了之后&#xff0c;将新数组赋值给HashMap对象的table属性 1.8版…

conda 复现论文部署环境常用操作

conda创建环境 conda create -n baichuan python3.9#不要创建环境&#xff0c;新创建的环境都没有关联cuda。可以复制原本就有cuda的环境 conda create -n 新环境名 --clone 旧环境名conda删除、查看环境 conda env list conda remove -n baichuan --all 停用环境 conda dea…

更新:彩虹云商城系统 自助下单免授权无后门源码(修复完整版)

源码简介&#xff1a; 最新更新彩虹云商城系统&#xff0c;自助下单免授权无后门源码&#xff08;修复完整版&#xff09; 自助下单彩虹云商城系统。这玩意儿不简单&#xff0c;它是高效稳定的电商平台&#xff01;免授权源码版本&#xff0c;灵活方便。源码是用PHP语言写的。…

如何在SpringCloud中优雅实现服务注册与发现

Spring Cloud提供了一个名为Eureka的服务注册与发现组件&#xff0c;可以帮助我们在微服务架构中实现服务注册与发现的功能。在本文中&#xff0c;我将介绍如何在Spring Cloud中使用Eureka实现服务注册与发现&#xff0c;并通过一些优雅的方式来进行配置和使用。 首先&#xf…

定期整理pycharm相关缓存

缘起&#xff1a;下载一个数据集之后&#xff0c;点了虚拟机&#xff0c;直接卡住了&#xff0c;第二屏黑了&#xff0c;然后放到桌面&#xff0c;用电脑管家查了下&#xff0c;结果一直再查pycharm下的remote_sources https://blog.csdn.net/lt_BeiMo/article/details/124159…

迅为3A5000_7A2000ATX标准DIY国产龙芯电脑

性能强 采用全国产龙芯3A5000处理器&#xff0c;基于龙芯自主指令系统 (LoongArch)的LA464微结构&#xff0c;并进一步提升频率&#xff0c;降低功耗&#xff0c;优化性能。 桥片 采用龙芯 7A2000&#xff0c;支持PCIE 3.0、USB 3.0和 SATA 3.0.显示接口2 路、HDMI 和1路 VGA&a…

超算网络体系架构-资源层-平台层-服务层-应用层

目录 超算网络体系架构 我国超算基础设施 超算互联网相关标准研制方面 技术架构 资源层 基础资源 芯片多样 体系异构 高效存储 高速互连 资源池化 可隔离 可计量 互联网络 高带宽 低时延 高安全 平台层 算力接入 资源管理 算力调度 用户管理 交易管理 模…