Java NIO 深度解析:构建高效的 I/O 操作
在 Java 编程领域,I/O 操作一直是至关重要的部分,它直接影响着应用程序的性能和响应能力。Java NIO(New I/O)作为传统 I/O 的增强版本,为处理大量并发连接和高效的数据传输提供了更强大的工具和机制。本文将深入探讨 Java NIO 的核心概念、关键组件以及如何运用它来构建高性能的 I/O 应用程序。
一、Java NIO 概述
Java NIO 是在 Java 1.4 中引入的一套全新的 I/O API,它与传统的 Java I/O(基于流的 I/O)有所不同。NIO 采用了基于通道(Channel)和缓冲区(Buffer)的非阻塞式 I/O 模型,这种模型能够在处理大量并发连接时表现出更好的性能和可扩展性。
传统的 I/O 操作在进行数据读取或写入时,往往会阻塞当前线程,直到操作完成。这在处理高并发场景时,会导致大量线程处于等待状态,浪费系统资源并降低应用程序的吞吐量。而 Java NIO 的非阻塞特性允许线程在等待 I/O 操作完成的过程中执行其他任务,从而提高了系统的资源利用率和响应速度。
二、核心组件
1. 通道(Channel)
通道是 NIO 中数据传输的载体,类似于传统 I/O 中的流,但具有更高的抽象层次和更多的功能。通道可以用于读取和写入数据,并且支持双向操作。常见的通道类型包括:
- FileChannel:用于文件的读写操作。可以从文件中读取数据到缓冲区,或者将缓冲区中的数据写入到文件。
- SocketChannel:用于网络套接字的读写操作。可以与远程服务器建立连接,并进行数据传输。
- ServerSocketChannel:用于监听网络端口,接受客户端的连接请求,并创建对应的
SocketChannel
实例。
例如,使用 FileChannel
读取文件的示例代码如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class FileChannelExample {public static void main(String[] args) {try {File file = new File("test.txt");FileInputStream fis = new FileInputStream(file);FileChannel channel = fis.getChannel();ByteBuffer buffer = ByteBuffer.allocate((int) file.length());channel.read(buffer);buffer.flip();while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}channel.close();fis.close();} catch (IOException e) {e.printStackTrace();}}
}
在上述示例中,首先通过 FileInputStream
获取对应的 FileChannel
,然后创建一个 ByteBuffer
缓冲区,将文件数据读取到缓冲区中,并最后将缓冲区中的数据打印出来。
2. 缓冲区(Buffer)
缓冲区是用于存储数据的容器,在 NIO 中所有的数据读写操作都是通过缓冲区来完成的。缓冲区具有以下几个重要属性:
- 容量(Capacity):缓冲区能够容纳的最大数据量。
- 位置(Position):当前缓冲区中数据的读写位置。
- 限制(Limit):缓冲区中可操作数据的边界。
常见的缓冲区类型有 ByteBuffer
、CharBuffer
、IntBuffer
等,分别用于处理不同类型的数据。例如,ByteBuffer
可以用于存储字节数据,适用于大多数通用的 I/O 操作。
以下是一个简单的 ByteBuffer
使用示例,展示了数据的写入和读取过程:
import java.nio.ByteBuffer;public class ByteBufferExample {public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(1024);// 写入数据到缓冲区buffer.put((byte) 'H');buffer.put((byte) 'e');buffer.put((byte) 'l');buffer.put((byte) 'l');buffer.put((byte) 'o');// 切换缓冲区为读模式buffer.flip();// 从缓冲区读取数据while (buffer.hasRemaining()) {System.out.print((char) buffer.get());}}
}
在这个示例中,首先分配了一个容量为 1024 的 ByteBuffer
,然后向其中写入了字符串 "Hello" 的字节数据,接着通过 flip
方法切换缓冲区为读模式,最后循环读取并打印缓冲区中的数据。
3. 选择器(Selector)
选择器是 NIO 实现非阻塞 I/O 的关键组件。它可以同时监听多个通道的事件,例如连接就绪、读就绪、写就绪等事件。通过使用选择器,单个线程可以管理多个通道的 I/O 操作,从而实现高效的并发处理。
以下是一个使用 Selector
实现简单的网络服务器示例,该服务器可以同时处理多个客户端连接:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NIOServer {public static void main(String[] args) throws IOException {// 创建 ServerSocketChannelServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8888));serverSocketChannel.configureBlocking(false);// 创建 SelectorSelector selector = Selector.open();// 将 ServerSocketChannel 注册到 Selector 上,监听连接事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {// 阻塞等待事件发生selector.select();// 获取发生事件的 SelectionKey 集合Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();if (key.isAcceptable()) {// 处理连接事件ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel socketChannel = server.accept();socketChannel.configureBlocking(false);// 将新连接的 SocketChannel 注册到 Selector 上,监听读事件socketChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {// 处理读事件SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int numRead = socketChannel.read(buffer);if (numRead == -1) {// 客户端关闭连接socketChannel.close();} else {buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);System.out.println("Received from client: " + new String(data));// 处理完数据后,将数据写回客户端buffer.flip();socketChannel.write(buffer);}}}}}
}
在这个示例中,首先创建了 ServerSocketChannel
并绑定到指定端口,将其设置为非阻塞模式后注册到 Selector
上监听连接事件。然后进入一个循环,通过 selector.select()
阻塞等待事件发生。当有事件发生时,遍历 selectedKeys
集合,根据事件类型分别处理连接事件和读事件。对于读事件,从客户端读取数据并打印,然后将数据写回客户端。
三、NIO 的优势与应用场景
1. 优势
- 非阻塞 I/O:减少线程阻塞等待时间,提高系统资源利用率和并发处理能力。
- 缓冲区操作:直接对缓冲区进行数据处理,减少数据复制次数,提高数据传输效率。
- 多路复用:通过选择器实现单个线程管理多个通道,降低系统开销,适用于高并发网络应用。
2. 应用场景
- 网络编程:如高性能的 Web 服务器、网络代理服务器、即时通讯软件等,需要处理大量并发连接的场景。
- 文件处理:对于大文件的读写操作,NIO 能够提供更高效的方式,例如文件上传下载、文件系统监控等。
四、总结
Java NIO 通过引入通道、缓冲区和选择器等核心组件,为 Java 开发者提供了一种高效、灵活的 I/O 处理方式。它在处理高并发和大数据量的 I/O 操作时表现出色,能够显著提升应用程序的性能和可扩展性。理解和掌握 Java NIO 的原理和使用方法,对于开发高性能的网络应用和处理大规模数据的程序具有重要意义。希望本文能够帮助读者深入了解 Java NIO,并在实际项目中充分发挥其优势,构建出更加健壮和高效的 Java 应用程序。
相关文章:
Java NIO 深度解析:构建高效的 I/O 操作
在 Java 编程领域,I/O 操作一直是至关重要的部分,它直接影响着应用程序的性能和响应能力。Java NIO(New I/O)作为传统 I/O 的增强版本,为处理大量并发连接和高效的数据传输提供了更强大的工具和机制。本文将深入探讨 J…...

总结拓展十六:特殊采购业务——VMI采购模式
1、VMI的定义 VMI采购模式(Vendor Managed Inventory)是一种合作性策略,旨在通过供应商管理库存,使供应链中的企业和供应商双方都能获得最低成本。在这种模式下,供应商根据共享的用户企业库存和实际耗用数据&#x…...
vue2 + iview(view-design) 中封装使用 vxe-table 处理表格渲染大量数据卡顿现象
今天遇到需求,iview组件分页每页100页时候页面卡顿现象严重,改造为使用vxe-table cell-mouseenter"handleCellMouseEnter" cell-mouseleave"handleCellMouseLeave" 这两个用来处理vxe-table 内容过多鼠标悬浮上去滚动 tooltip直接…...

初学者指南:知识库问答(KBQA)多跳路径的核心与应用
初学者指南:知识库问答(KBQA)多跳路径的核心与应用 知识库问答(Knowledge Base Question Answering, KBQA)旨在利用结构化知识库(如Wikidata、Freebase)回答自然语言问题。在实际应用中&#x…...

创建springboot+vue项目相关配置问题
安装并配置jdk23 在官网下载jdk Java Downloads | Oracle 中国 下载完成后双击即可安装。 安装完成后配置环境变量 此电脑->右键->属性->高级系统设置 然后一直点击确定即可。 键盘上win r java -version 可以验证是否配置成功 下载并配置maven 在官网下…...

基于AOA算术优化的KNN数据聚类算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于AOA算术优化的KNN数据聚类算法matlab仿真。通过AOA优化算法,搜索最优的几个特征数据,进行KNN聚类,同时对比不同个数特征下…...

【机器学习】在泊松分布中,当λ值较大时,其近似正态分布的误差如何评估?
在泊松分布中,当参数 λ 较大时,其近似正态分布的有效性可以通过 中心极限定理 和误差分析来理解和评估。以下内容结合理论推导和实际案例展开说明: 1. 泊松分布的定义 泊松分布是用于建模单位时间或单位空间内随机事件发生次数的概率分布&a…...

ABAP开发-面向对象开发_2
系列文章目录 文章目录 系列文章目录[TOC](文章目录) 前言接口和类1、首先创建一个接口2、在创建的接口的基础上创建一个类PERSON3、创建子类STUDENT4、创建子类TEACHER5、SE38使用创建的类 总结 前言 接口和类 全局类 SE24 创建一个接口-》创建一个实现接口的类-》再创建两个…...

微信小程序-prettier 格式化
一.安装prettier插件 二.配置开发者工具的设置 配置如下代码在setting.json里: "editor.formatOnSave": true,"editor.defaultFormatter": "esbenp.prettier-vscode","prettier.documentSelectors": ["**/*.wxml"…...
241118学习日志——[CSDIY] [ByteDance] 后端训练营 [06]
CSDIY:这是一个非科班学生的努力之路,从今天开始这个系列会长期更新,(最好做到日更),我会慢慢把自己目前对CS的努力逐一上传,帮助那些和我一样有着梦想的玩家取得胜利!!&…...

Android WMS概览
WMS(WindowManagerService)是 Android 系统的核心服务,负责管理应用和系统的窗口,包括窗口的创建、销毁、布局、层级管理、输入事件分发以及动画显示等。它通过协调 InputManager 和 SurfaceFlinger 实现触摸事件处理和窗口渲染&a…...

新一代API开发工具,让API调试更快 更简单
新一代API开发工具 代理调试 请求测试一站式解决方案 Reqable Fiddler Charles Postman, 让API调试更快 🚀 更简单 👌 直接上下载地址 根据系统,下载对应的版本即可 https://reqable.com/zh-CN/download/...
友元类和友元函数
友元函数的定义: 友元函数是在类定义中被声明为 “朋友” 的非成员函数。它可以访问类的私有成员和保护成员(变量和方法),就好像它是类的成员函数一样。友元函数的声明以friend关键字开头,在类的内部进行声明,但它的定义在类的外部ÿ…...

Sulfo-Cy5-Iodoacetamide能够发出明亮的荧光信号,使得生物样本的精细结构得以清晰呈现
一、基本信息 英文名称:Sulfo-Cy5-Iodoacetamide,Sulfo-Cyanine5-Iodoacetamide,Sulfo Cy5 IA 中文名称:磺酸Cy5碘乙酰胺 分子式:C36H44IKN4O8S2 分子量:890.89 纯度:≥95% 外观ÿ…...

Python中的TCP
文章目录 一. 计算机网络1. 网络的概念2. IP地址① IP地址的概念② IP地址的表现形式③ IP地址的作用④ 网络查询命令Ⅰ. ifconfig/ipconfigⅡ. ping 3. 端口和端口号的概念(计算机通信原理)① 端口的概念② 端口号的概念 4. socket套接字① socket概念② socket使用场景 二. T…...

CSS(8)高级技巧:精灵图,css三角,用户界面,vertical-align属性应用
一.精灵图 通过css中的background-position属性,将多张图合成为一张图 二.css三角 在网页中,我们可以添加css属性获得三角图标 solid:实心,边框的实心 transparent:透明,图中代码表示只有左边粉色,其余地方为透明 三ÿ…...

Flink新版Source接口源码解析
目录 1. 前言 2. Source解析 2.1 Source类图 2.2 接口和方法说明 2.2.1 Source,> 3. SplitEnumerator解析 3.1 SplitEnumetator类图 3.2 类和方法说明 3.2.1 SplitEnumerator 3.2.2 SimpleVersionedSerializer 4. SourceReader解析 4.1 SourceReader类图 4.2 类…...

SLM561A系列60V10-50mA单通道线性恒流LED驱动芯片,为汽车照明、景观照明助力
SLM561A系列选型参考: SLM561A10ae-7G SOD123 SLM561A15ae-7G SOD123 SLM561A20ae-7G SOD123 SLM561A25ae-7G SOD123 SLM561A30ae-7G SOD123 SLM561A35ae-7G SOD123 SLM561A40ae-7G SOD123 SLM561A45ae-7G SOD123 SLM561A50ae-7G SOD123 S…...

一次失败的wxpython安装macOS M1
WARNING: The scripts libdoc, rebot and robot are installed in /Users/用户名/Library/Python/3.8/bin which is not on PATH. 背景:想在macos安装Robot Framework ,显示pip3不是最新,更新pip3后显示不在PATH上 参看博主文章末尾 MAC系统…...

【大数据技术基础 | 实验十一】Hive实验:新建Hive表
文章目录 一、实验目的二、实验要求三、实验原理四、实验环境五、实验内容和步骤(一)启动Hive(二)创建表(三)显示表(四)显示表列(五)更改表(六&am…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...