Java中常见的 IO 方式

news2024/11/24 17:39:10

        冯·诺依曼结构中计算机结构被分为 5 大部分:运算器、控制器、存储器、输入设备、输出设备,输入设备向计算机输入数据,输出设备接收计算机输出的数据。从计算机结构的视角来看的话, I/O 描述了计算机系统与外部设备之间通信的过程。输入设备(比如键盘)和输出设备(比如显示器)都属于外部设备。 网卡、硬盘这种既可以属于输入设备,也可以属于输出设备。

        所谓 IO 即 输入输出,是操作系统为了保证操作系统的稳定性和安全性,将一个进程的地址空间划分为 用户空间(User space  内核空间(Kernel space  。我们运行的应用程序都是运行在用户空间,而只有内核空间才能进行系统态级别的资源有关的操作,比如文件管理、进程通信、内存管理等等。我们想要进行 IO 操作,一定是要依赖内核空间的能力。并且,用户空间的程序不能直接访问内核空间。当想要执行 IO 操作时,由于没有执行这些操作的权限,只能发起系统调用请求操作系统帮忙完成。因此,用户进程想要执行 IO 操作的话,必须通过 系统调用 来间接访问内核空间,而我们常见的 IO主要是磁盘 IO(读写文件)  网络 IO(网络请求和响应)。

        从应用程序的视角来看的话,我们的应用程序对操作系统的内核发起 IO 调用(系统调用),而具体的IO 操作则是系统的内核来执行。 当应用程序发起 I/O 调用后,会经历两个步骤:

  • 内核等待 I/O 设备准备好数据
  • 内核将数据从内核空间拷贝到用户空间。

1、IO 的分类

        IO读写操作实际上 Read 系统调用是将数据从内核空间复制到用户空间;write系统调用是将数据从用户空间复制到内核空间;底层都是由内核来完成的。UNIX 系统下的 IO 模型一共有同步阻塞 I/O、同步非阻塞 I/OI/O 多路复用、信号驱动 I/O 和异步 I/O 5 种而信号驱动 I/O 使用中并不多见,这里不多做介绍了

        java中的 IO 在 Java 1.4 中引入了 NIO 框架(java.nio 包),提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层的高性能数据操作方式。在 Java 7 中时,NIO 有了进一步的改进,也就是 NIO 2,引入了异步非阻塞 IO 方式,也有很多人叫它 AIO(Asynchronous IO)。异步 IO 操作基于事件和回调机制,可以简单理解为,应用操作直接返回,而不会阻塞在那里,当后台处理完成,操作系统会通知相应线程进行后续工作。

a、同步阻塞 I/O

        当用户程序执行 read ,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回。阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程,在客户端连接数量不高的情况下,是没问题的。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。

工作原理

  • 进程发起 I/O 请求后,会一直等待,直到数据传输完成。
  • 在数据传输期间,进程被挂起,无法执行其他任务。

  • 应用进程向内核发起 read 读取数据
  • 等待内核缓冲区数据(阻塞)
  • 内核缓冲区数据准备好后,复制数据到用户缓冲区(阻塞)
  • 复制完成,返回成功

java中的实现

ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept(); // 阻塞直到有连接
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) { // 阻塞直到数据可读
    // 处理数据
}
b、同步非阻塞 NI/O 

        非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read 调用才可以获取到结果。

工作原理

  • 进程发起 I/O 请求后,如果数据未准备好,请求会立即返回一个错误码。
  • 进程需要不断轮询来检查数据是否准备好。

  • 应用进程向内核发起 read 读取数据
  • 数据没有准备好,直接返回 EWOULDBLOCK 错误(非阻塞)
  • 应用进程不断发起 read 读取数据
  • 内核缓冲区数据准备好后,将数据复制到用户缓冲区(阻塞)
  • 复制完成,返回成功

java中的实现

SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false); // 设置为非阻塞模式
socketChannel.connect(new InetSocketAddress("example.com", 80));
while (!socketChannel.finishConnect()) {
    // 非阻塞模式下,连接尚未完成,可以做其他事情
}
// 连接建立后,进行数据读写
 c、I/O 多路复用

        使用 select、poll、epoll 等系统调用,进程可以监视多个文件描述符,一旦某个文件描述符就绪(读写操作不会阻塞),则能够通知进程进行相应的读写操作。JAVA 中的 NIO 是使用的 IO 多路复用,Linux环境下底层使用的是 epoll。该模型适用于连接数多,连接时间短的场景,select阻塞,等待所有socket中的任意一个变成可读

工作原理

  • 使用单个线程来监控多个文件描述符的 I/O 状态。
  • 当某个文件描述符就绪时,线程会被唤醒来执行 I/O 操作。

  • 进程受阻于select调用,等待多个 socket 中的任意一个变为可读(阻塞)
  • 当socket变成可读时(说明内核缓冲区数据已经准备好),用户进程发起read读取数据,将数据复制到用户缓冲区(阻塞)
  • 复制完成,返回成功

java中的实现

Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress(portNumber));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
    int readyChannels = selector.select();
    if (readyChannels == 0) continue;
    Set<SelectionKey> selectedKeys = selector.selectedKeys();
    Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
    while (keyIterator.hasNext()) {
        SelectionKey key = keyIterator.next();
        if (key.isAcceptable()) {
            // 处理接受连接
        } else if (key.isReadable()) {
            // 处理读
        }
        keyIterator.remove();
    }
}
d、异步 I/O

        进程发起异步 I/O 操作后,可以立即返回继续执行其他任务。当整个 I/O 操作(包括数据准备和传输)完成时,进程会收到一个信号或者其他形式的通知。

工作原理

  • 进程发起异步 I/O 操作后,可以立即返回继续执行其他任务。
  • 当整个 I/O 操作完成时,进程会收到通知。

java中的实现

AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("data.txt"), StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        // 读取完成时的处理
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        // 读取失败时的处理
    }
});
// 继续执行其他任务,不需要等待 I/O 完成

       异步 I/O 模型虽然提供了非阻塞操作和高性能的潜力,但由于其编程复杂性、平台依赖性、调试难度以及对现有同步系统的重构成本,它并没有被广泛使用和推广。然而,在特定的高并发和 I/O 密集型应用场景中,异步 I/O 仍然是一个重要且有价值的工具

2、总结对比

优点缺点
同步阻塞 I/O

- 编程模型简单,易于理解和实现

- 适合连接数较少且持续时间短的应用

- I/O 操作会阻塞线程,效率低下,不适合高并发场景

- 线程资源消耗大,每个连接都需要一个线程来处理

同步非阻塞 I/O

- 允许单线程管理多个连接,提高资源利用率

- 线程可以在没有数据可读写时执行其他任务

- 编程模型复杂,需要处理轮询逻辑。

- 高负载下,CPU 轮询消耗可能会增加

I/O 多路复用

- 单线程或少量线程就可以处理多个客户端连接,适合高并发场景。

- 通过减少线程数量,降低了资源消耗。

- 编程模型相对复杂,需要维护多个文件描述符和事件。

- 在某些实现(如 select)中,有文件描述符数量限制

异步 I/O

- 真正的异步,应用程序无需等待 I/O 完成,可以立即处理其他任务。

- 提高了程序的吞吐量和响应性

- 编程模型最为复杂,需要处理回调或者 Future 对象。

- 系统实现复杂,依赖操作系统的支持。

        同步阻塞 I/O 适合简单的应用场景,而 I/O 多路复用和异步 I/O 更适合高并发和高吞吐量的场景。同步非阻塞 I/O  和信号驱动 I/O 在实际应用中较少见,通常被 I/O 多路复用和异步 I/O 所取代。

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

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

相关文章

JMeter VS RunnerGo :两大主流性能测试工具对比

说起JMeter&#xff0c;估计很多测试人员都耳熟能详。它小巧、开源&#xff0c;还能支持多种协议的接口和性能测试&#xff0c;所以在测试圈儿里很受欢迎&#xff0c;也是测试人员常用的工具&#xff0c;不少企业也基于JMeter建立起自己的自动化测试能力&#xff0c;提升工作效…

体验Node.js的安装和运行

Node.js概述 Node.js是一个基于Chrome V8引擎的JavaScript运行环境。它允许JavaScript代码在服务器端运行&#xff0c;使得开发人员可以使用同一种语言编写前端和后端的代码。Node.js使用事件驱动、非阻塞I/O模型&#xff0c;使其轻量且高效&#xff0c;非常适合数据密集型的实…

java性能调优面试,程序员Java视频

前言 很多人在打算自学Java的时候或许都没有思考过Java的应用方向&#xff0c;市场需要什么样的人才&#xff0c;企业对你有什么要求等等一系列问题&#xff1b;或许你只听说这个行业薪资高…然后懵懵懂懂的上路&#xff0c;不得要害。 对于零基础来学习Java&#xff0c;你或…

怎样才能考上南京大学的计算机研究生?

附上南大与同层次学校近四年的分数线对比&#xff0c;整体很难 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 我本人是双非一本的计算机专业&#xff0c;23考研一战上岸的&#xf…

【C语言】还有柔性数组?

前言 也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#xff0c;但是它确实是存在的。C99中&#xff0c;结构中的最后⼀个元素允许是未知⼤⼩的数组&#xff0c;这就叫做『柔性数组』成员。 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xf…

LinkedList集合源码分析

LinkedList集合源码分析 文章目录 LinkedList集合源码分析一、字段分析二、构造函数分析三、方法分析四、总结 看到实现了Deque 就要联想到这个数据结构肯定是属于双端队列了。Queue 表示队列&#xff0c;Deque表示双端队列。 一、字段分析 LinkedList 字段很少&#xff0c;就…

Vector Search和专用Search Nodes:现已正式发布

我们非常高兴地推出了 Atlas Vector Search 和 Search Nodes 的正式发布版本 (GA)&#xff0c;为 Atlas 平台增添了更多价值。 自从在公开预览版中发布 Atlas Vector Search 和带有 Search Nodes 的专用基础架构以来&#xff0c;我们注意到&#xff0c;对于使用向量优化搜索节…

【数据集】MSWEP(多源加权集合降水)再分析数据

MSWEP全球降水数据 数据概述数据下载参考数据概述 MSWEP(Multi-Source Weighted-Ensemble Precipitation)降水数据集是一种高分辨率、全球覆盖的降水数据产品,它融合了多种来源的降水信息,包括卫星遥感数据、雷达观测、地面气象站观测数据以及数值天气预报模型的输出。MSW…

C switch 语句

一个 switch 语句允许测试一个变量等于多个值时的情况。每个值称为一个 case&#xff0c;且被测试的变量会对每个 switch case 进行检查。 语法 C 语言中 switch 语句的语法&#xff1a; switch(expression){case constant-expression :statement(s);break; /* 可选的 */ca…

Redis线程模型解析

引言 Redis是一个高性能的键值对&#xff08;key-value&#xff09;内存数据库&#xff0c;以其卓越的读写速度和灵活的数据类型而广受欢迎。在Redis 6.0之前的版本中&#xff0c;它采用的是一种独特的单线程模型来处理客户端的请求。尽管单线程在概念上似乎限制了其扩展性和并…

C++ 之AVL树

AVL树 AVL树的基本概念AVL树的平衡因子、AVL树的旋转avl的双旋旋转的4种情况 AVL树的基本概念 AVL树的平衡因子、 AVL树的旋转 当平衡因子的高度差过大时&#xff0c;就要选择。所谓的选择其实也是一种压扁的操作 在本例中 新插入的蓝色结点使得不在平衡。 我们看上图就能…

【CSP试题回顾】201604-1-折点计数

CSP-201604-1-折点计数 解题代码 #include <iostream> #include <vector> #include <algorithm> using namespace std;int n, pointSum;int main() {cin >> n;vector<int>myData(n);for (int i 0; i < n; i){cin >> myData[i];}// 统…

深色系可视化界面看腻了,来点浅色系?安排,20页来了。

只要不放在大屏上展示&#xff0c;贝格前端工场还是非常推崇浅色系的可视化界面&#xff0c;把它作为配色的首选 。浅色系可视化界面具有以下几个优势&#xff1a; 清晰明了 浅色系界面通常使用明亮的颜色&#xff0c;如白色、浅灰色等&#xff0c;使界面元素更加清晰可见。这…

文件MD5校验码的安全性及重要性

title: 文件MD5校验码的安全性及重要性 date: 2024/3/6 18:13:20 updated: 2024/3/6 18:13:20 tags: MD5原理文件校验下载验证数据库一致性安全性保障计算方法MD5安全防护 文件MD5&#xff08;Message Digest Algorithm 5&#xff09;是一种常用的哈希算法&#xff0c;用于验证…

Docker部署(ruoyi案例接上篇Docker之部署前后端分离项目)实施必会!!!!

文章目录 Docker部署前端 Docker部署前端 接上篇博主已经部署好后端Docker部署后端&#xff0c;现在来讲解怎么部署前端 MySQL和redis是不依赖其他任何一个东西的&#xff0c; ruoyi-admin是因为你启动项目的时候是必须连接数据库的 现在去单独启动它 docker start ruoyi-a…

Python爬虫:设置随机 User-Agent

Python爬虫&#xff1a;设置随机 User-Agent 在Python中编写爬虫时&#xff0c;为了模拟真实用户的行为并防止被服务器识别为爬虫&#xff0c;通常需要设置随机的User-Agent。你可以使用fake-useragent库来实现这一功能。首先&#xff0c;你需要安装fake-useragent库&#xff…

【web网页制作】html+css网页制作企业网站办公用品主题(3页面)【附源码】

企业网站目录 涉及知识写在前面一、网页主题二、网页效果Page1、主页Page2、用品展示Page3、关于我们 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 四、网页源码4.1 主页模块源码4.2 源码获取方式 作者寄语 涉及知识 办公用品企业主题HTML网页制作&#xff0c;…

进程调度算法(先来先服务/短作业优先)代码实现

最近在复习408操作系统进程时&#xff0c;决定用代码模拟调度算法来熟悉详细过程! 选择两个好写点的算法进行练习!!! 以下代码使用c语言。优先队列和队列直接使用STL容器!!! 引入头文件 #include<iostream> #include<queue> #include<map> using namespace …

【漏洞复现】ShopXO任意文件读取漏洞

Nx01 产品简介 ShopXO是一套开源的企业级开源电子商务系统&#xff0c;包含PC、H5、微信小程序、支付宝小程序、百度小程序等多个终端&#xff0c;遵循Apache2开源协议发布&#xff0c;基于ThinkPHP5.1框架研发。该系统具有求实进取、创新专注、自主研发、国内领先企业级B2C电商…

基于stm32的电压采样与质量检测系统

150基于stm32的电压采样与质量检测系统[proteus仿真] 电压检测系统这个题目算是课程设计和毕业设计中常见的题目了&#xff0c;本期是一个基于stm32的电压采样与质量检测系统 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】&#xff0c;赞赏任意文章 2&#xf…