什么是NIO
NIO(New Input/Output),也称为Java非阻塞IO,是从Java 1.4版本开始引入的一个新的IO API,旨在提供一种比传统的阻塞IO更高效、更灵活的IO操作方式。
一 NIO用法的详细介绍
NIO支持面向缓冲区的、基于通道的IO操作,其核心组件包括缓冲区(Buffer)、通道(Channel)和选择器(Selector)。
1.1 缓冲区(Buffer)
缓冲区是NIO中用于存储数据的对象,它是一个固定大小的内存区域,可以用来读取数据和写入数据。NIO提供了多种类型的缓冲区,如ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer和DoubleBuffer等,用于存储不同类型的数据。
缓冲区的主要属性和方法包括:
- 容量(Capacity):表示缓冲区可以存储的最大数据量,一旦声明就不能改变。
- 限制(Limit):表示缓冲区中可以操作数据的大小(limit后面的数据不能读写)。
- 位置(Position):表示缓冲区中正在操作数据的位置。
- 标记(Mark):表示记录当前position的位置,可以通过reset()恢复到mark的位置。
缓冲区的主要方法有:
- put():向缓冲区中写入数据。
- get():从缓冲区中读取数据。
- flip():将缓冲区的界限设置为当前位置,并将当前位置重置为0,用于切换读写模式。
- rewind():将位置重置为0,取消设置的mark。
- clear():清空缓冲区,但不清空数据,准备下一次读写操作。
1.2 通道(Channel)
通道是NIO中用于数据读写的通道,它可以与文件、网络套接字等进行交互。通道是双向的,既可以用于读操作也可以用于写操作,并且支持非阻塞模式。与传统的IO流不同,通道与缓冲区配合使用,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
NIO中主要的通道类型有:
- FileChannel:用于文件的读写操作。
- SocketChannel:用于网络套接字的读写操作(TCP协议)。
- ServerSocketChannel:用于监听传入的TCP连接。
- DatagramChannel:用于UDP数据包的发送和接收。
1.3 选择器(Selector)
选择器是NIO的一个核心组件,它允许单个线程同时处理多个通道(Channel)的IO事件。通过选择器,可以监听多个通道的状态变化(如连接打开、数据到达等),并在这些事件发生时进行相应的处理。这样,一个线程就可以管理多个网络连接,提高了系统的并发性能。
使用选择器的一般步骤包括:
- 打开选择器。
- 将通道注册到选择器上,并指定要监听的事件类型(如读就绪、写就绪等)。
- 调用选择器的select()方法,该方法会阻塞,直到有一个或多个通道发生了注册的事件。
- 遍历选择器的已选择键集合(SelectedKeySet),对每个键进行处理。
- 更新键的状态,并可能重新注册感兴趣的事件。
NIO通过缓冲区、通道和选择器提供了一种高效、灵活的IO操作方式。它适用于需要处理大量并发连接的网络编程和高性能服务器开发等场景。通过合理地使用缓冲区、通道和选择器,可以显著提高系统的并发性能和吞吐量。
二 对NIO优缺点的详细介绍
NIO(New Input/Output)作为Java中一种新的IO处理方式,相较于传统的BIO(Blocking Input/Output)具有一系列的优点,但同时也存在一些潜在的缺点。
2.1 优点
- 非阻塞IO:
NIO最大的优点之一就是其支持非阻塞IO操作。在传统的BIO中,当一个线程进行IO操作时,如果该操作需要等待(如等待数据从网络到达),则该线程会被阻塞,直到IO操作完成。而在NIO中,线程可以在等待IO操作完成时继续执行其他任务,从而提高了系统的资源利用率和吞吐量。 - 选择器(Selector)机制:
NIO引入了选择器的概念,允许单个线程同时处理多个通道(Channel)的IO事件。通过选择器,我们可以注册多个通道并监听它们的事件(如读就绪、写就绪等),当某个通道的事件发生时,选择器会通知我们,然后我们可以对这些事件进行处理。这种方式极大地减少了线程的数量,降低了线程切换的开销。 - 缓冲区(Buffer)的使用:
NIO通过缓冲区来处理数据,这减少了直接对IO资源的操作次数。数据首先被读入缓冲区,然后再从缓冲区中读取或写入到通道中。缓冲区可以重复使用,减少了内存分配和回收的开销。 - 更高的并发性能:
由于NIO支持非阻塞IO和选择器机制,因此它可以在单个线程中处理多个连接,从而提高了系统的并发处理能力。这使得NIO成为构建高性能网络服务器和客户端的理想选择。 - 更灵活的IO操作:
NIO提供了更灵活的IO操作方式,如文件映射(File Mapping)和内存映射文件(Memory-Mapped File)等。这些特性使得NIO在处理大文件和网络IO时更加高效。
2.2 缺点
- 学习曲线较陡:
相对于传统的BIO,NIO的API更加复杂,需要更多的时间来学习和掌握。这包括理解缓冲区、通道和选择器的概念以及它们之间的关系。 - 编程复杂度较高:
由于NIO提供了更多的灵活性和控制能力,因此在使用NIO进行编程时需要更多的代码和逻辑来处理各种情况。这可能会增加程序的复杂度和出错的可能性。 - 缓冲区管理:
缓冲区管理是NIO中的一个重要方面,但也是一个潜在的缺点。程序员需要负责缓冲区的分配、使用和释放,这可能会引入内存泄漏等问题。此外,缓冲区的大小也需要根据实际应用场景进行仔细的选择和调整。 - 性能调优:
为了充分利用NIO的性能优势,需要对缓冲区大小、线程数量、选择器使用等进行仔细的性能调优。这可能需要一定的时间和经验来找到最优的配置。 - 兼容性:
在某些情况下,NIO可能与现有的基于BIO的库或框架不兼容。这可能会增加迁移或集成现有系统的难度和成本。
总的来说,NIO作为Java中一种新的IO处理方式,具有显著的性能优势和灵活性。然而,它也带来了一定的学习曲线和编程复杂度。因此,在选择使用NIO时,需要根据实际应用场景和需求进行权衡和考虑。
三 NIO网络编程示例
NIO(New Input/Output)网络编程通常涉及到非阻塞的IO操作,这使得单个线程可以管理多个网络连接。以下是一个更完整的NIO网络编程示例,包括一个简单的服务器和客户端。这个示例将展示如何使用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 { Selector selector = Selector.open(); // 打开ServerSocketChannel ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); // 绑定端口并监听 serverChannel.socket().bind(new InetSocketAddress(8000)); // 注册到selector,监听ACCEPT事件 serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); 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()) { // 接受新的连接 ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel client = server.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); System.out.println("Accepted new connection from " + client); } else if (key.isReadable()) { // 读取数据 SocketChannel client = (SocketChannel) key.channel(); buffer.clear(); int bytesRead = client.read(buffer); if (bytesRead > 0) { buffer.flip(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); String received = new String(data, "UTF-8"); System.out.println("Received: " + received); // 这里可以添加将数据写回客户端的逻辑 } } keyIterator.remove(); } } }
}
客户端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class NIOClient { public static void main(String[] args) throws IOException { // 打开SocketChannel SocketChannel client = SocketChannel.open(); client.configureBlocking(false); // 连接到服务器 client.connect(new InetSocketAddress("localhost", 8000)); // 等待连接完成 while (!client.finishConnect()) { // 这里可以做一些其他事情,比如处理其他IO操作 } // 发送数据到服务器 String newData = "Hello from Client"; ByteBuffer buffer = ByteBuffer.wrap(newData.getBytes("UTF-8")); while (buffer.hasRemaining()) { client.write(buffer); } // 关闭SocketChannel client.close(); }
}
注意:
- 这个服务器示例在接收到数据后并没有将数据写回客户端。在实际应用中,你可能需要添加这样的逻辑来响应客户端的请求。
- 客户端在发送完数据后立即关闭了SocketChannel。在实际应用中,你可能希望保持连接以接收服务器的响应或进行进一步的通信。
- 服务器端在接收到数据后,会将其转换为字符串并打印出来。在生产环境中,你可能需要处理多种类型的数据和更复杂的协议。
- 这个示例没有处理异常和关闭资源(如Selector和ServerSocketChannel)的逻辑。在实际应用中,你应该在适当的时机关闭这些资源,并处理可能出现的异常。
相关文章:
什么是NIO
NIO(New Input/Output),也称为Java非阻塞IO,是从Java 1.4版本开始引入的一个新的IO API,旨在提供一种比传统的阻塞IO更高效、更灵活的IO操作方式。 一 NIO用法的详细介绍 NIO支持面向缓冲区的、基于通道的IO操作&…...
PHP switch 替代品 match
match 是 PHP 8 中引入的新特性。在 PHP 8 中,match 用作新的类型安全的替代 switch 语句。它提供了更清晰、更简洁的语法,同时还支持表达式作为条件,可以更轻松地处理复杂的条件逻辑。 在 match 表达式中,每个分支都是一个条件和…...
FastAPI(七十四)实战开发《在线课程学习系统》接口开发-- 删除留言
源码见:"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 之前文章FastAPI(七十三)实战开发《在线课程学习系统》接口开发-- 回复留言,那么我们这次分享删除留言接口的开发…...
面试重点---快速排序
快排单趟 快速排序是我们面试中的重点,这个知识点也很抽象,需要我们很好的掌握,而且快速排序的代码也是非常重要,需要我们懂了还不行,必须要手撕代码,学的透彻。 在研究快速排序之前,我们首先…...
[MIT6.5840]MapReduce
MapReduce Lab 地址 https://pdos.csail.mit.edu/6.824/labs/lab-mr.html 论文地址 https://static.googleusercontent.com/media/research.google.com/zh-CN//archive/mapreduce-osdi04.pdf 工作原理 简单来讲,MapReduce是一种分布式框架,可以用来处理…...
【系统架构设计师】计算机组成与体系结构 ⑯ ( 奇偶校验码 | CRC 循环冗余码 | 海明码 | 模 2 除法 )
文章目录 一、校验码1、校验码由来2、奇偶校验码3、CRC 循环冗余码 ( 重点考点 )4、海明码校验 ( 软考不经常考到 ) 二、CRC 循环冗余码 ( 重点考点 )1、模 2 除法概念2、模 2 除法步骤3、模 2 除法示例4、CRC 循环冗余码示例 15、CRC 循环冗余码示例 2 参考之前的博客 : 【计…...
springboot,service 层统一异常抛出时,throws Exception写在接口上还是实现类上
springboot,service 层统一异常抛出时,throws Exception写在实现接口上,不是直接写在实现类上...
深度学习高效性网络
为了减轻Transformer笨重的计算成本,一系列工作重点开发了高效的Vision Transformer,如Swin Transformer、PVT、Twins、CoAtNet和MobileViT。 1、字节TRT-ViT 兼具CNN的速度、Transformer精度的模型 TRT-ViT(Transformer-based Vision Tra…...
PyQt ERROR:ModuleNotFoundError: No module named ‘matplotlib‘
Solution:打开cmd输入指令下载malplotlib pip install matplotlib...
Flutter Geolocator插件使用指南:获取和监听地理位置
Flutter Geolocator插件使用指南:获取和监听地理位置 简介 geolocator 是一个Flutter插件,提供了一个简单易用的API来访问特定平台的地理位置服务。它支持获取设备的最后已知位置、当前位置、连续位置更新、检查设备上是否启用了位置服务,以…...
网站基本布局CSS
代码 <!DOCTYPE html> <html> <head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, initial-scale1"><title></title><style type"text/css">body {margi…...
ssm框架整合,异常处理器和拦截器(纯注解开发)
目录 ssm框架整合 第一步:指定打包方式和导入所需要的依赖 打包方法:war springMVC所需依赖 解析json依赖 mybatis依赖 数据库驱动依赖 druid数据源依赖 junit依赖 第二步:导入tomcat插件 第三步:编写配置类 SpringCon…...
古籍双层PDF制作教程:保姆级古籍数字化教程
在智慧古籍数字化项目中,很多图书馆要求将古籍导出为双层PDF,并且确保输出双层PDF底层文本与上层图片偏移量控制在1毫米以内。那么本教程带你使用古籍数字化平台,3分钟把一个古籍书籍转化为双侧PDF。 第1步:上传古籍 点批量上传…...
Git 删除 远端的分支
要删除 Git 远端的分支(例如: V3.2.1.13): 可以执行以下命令 git push origin --delete V3.2.1.13这条命令会向远端的仓库删除名为 V3.2.1.13 的分支。如果这个分支只在远端仓库存在而没有对应的本地分支,那么删除后这…...
PrgogressBar实现原理分析
ProgressBar 是 Android 中用于显示进度条的控件,它可以用来表示任务的完成程度或者加载进度等信息。ProgressBar 有两种主要类型:一种是确定性的(determinate),另一种是不确定性的(indeterminateÿ…...
【HarmonyOS】HarmonyOS NEXT学习日记:七、页面与组件的生命周期
【HarmonyOS】HarmonyOS NEXT学习日记:七、页面与组件的生命周期 页面和组件 组件:用Component装饰的代码称为自定义组件页面:Entry装饰的组件即页面的根节点 组件生命周期 aboutToAppear:在创建自定义组件的新实例后…...
【iOS】——Block循环引用
循环引用原因 如果在Block中使用附有_ _strong修饰符的对象类型自动变量,那么当Block从栈复制到堆时,该对象为Block所持有,这样容易引起循环引用。 HPPerson *person [[HPPerson alloc] init];person.block ^{NSLog("person.age--- …...
shell脚本自动化安装启动各种服务
1、自动化配置dns服务器 A主机:vim dns.sh #!/bin/bash# 自动化部署dns# 1、下载bind# 2、修改配置文件# vim /etc/named.conf # listen-on port 53 { 127.0.0.1;any; }; 修改(定位替换)# allow-query { localhost;any; }; 修改&am…...
Python - 开源库 ReportLab 库合并 CVS 和图像生成 PDF 文档
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/140281680 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 Report…...
Java编写SIP协议
1、编写Server代码 package com.genersoft.iot.vmp.sip; import javax.sip.*; import javax.sip.message.*; import javax.sip.header.*; import java.util.*;public class SimpleSipServer implements SipListener {private SipFactory sipFactory;private SipStack sipStack…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
