什么是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…...

大型语言模型LLM的核心概念
本文主要介绍了目前主流的,几个大型语言模型LLM的整个训练过程 通常分为下面的几个阶段 1. 预训练 采用互联网上的大量数据进行训练,这一阶段大模型LLM的主体已定,找出共性并且压缩成一个模型。模型的参数量不是越大越好,遵循合理…...

软件测试---网络基础、HTTP
一、网络基础 (1)Web和网络知识 网络基础TCP/IP 使用HTTP协议访问Web WWW万维网的诞生 WWW万维网的构成 (2)IP协议 (3)可靠传输的TCP和三次握手策略 (4)域名解析服务DNS ࿰…...

韩顺平0基础学java——第39天
p820-841 jdbc和连接池 1.JDBC为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节问题。 2.Java程序员使用JDBC,可以连接任何提供了JDBC驱动程序的数据库系统,从而完成对数据库的各种操作。 3.jdbc原理图 JDBC带来的好处 2.JDBC带来的…...

Linux文件恢复
很麻烦 一般还是小心最好 特别恢复的时候 可能不能选择某个文件夹去扫描恢复 所以 删除的时候 用rm -i代替rm 一定小心 以及 探索下linux的垃圾箱机制 注意 一定要恢复到不同文件夹 省的出问题 法1 系统自带工具 debugfs 但是好像不能重启? testdisk 1、安装 …...

大数据的数据质量有效提升的研究
大数据的数据质量有效提升是一个涉及多个环节和维度的复杂过程。以下是从数据采集、处理、管理到应用等方面,对大数据数据质量有效提升的研究概述: 一、数据采集阶段 明确采集需求:在数据采集前,需明确数据需求,包括…...

Flink-CDC解析(第47天)
前言 本文主要概述了Flink-CDC. 1. CDC 概述 1.1 什么是CDC? CDC是(Change Data Capture 变更数据获取)的简称 ,在广义的概念上,只要是能捕获数据变更的技术,都可以称之为 CDC。 核心思想是,…...

二阶段测试
二阶段测试 1、部署框架前准备工作 服务器类型部署组件ip地址DR1调度服务器 主(ha01)KeepalivedLVS-DR192.168.168.21DR2调度服务器 备 (ha02)KeepalivedLVS-DR192.168.168.22web1节点服务器 (slave01)NginxTomcatMySQL 备MHA managerMHA node192.168.1…...

CSP-J模拟赛day1——解析+答案
题目传送门 yjq的吉祥数 题解 送分题,暴力枚举即可 Code #include<bits/stdc.h> using namespace std;int l,r; int num1,tmp0,q[10000],a[10000]; int k (int x){for (int j1;j<tmp;j){if (xq[j])return 0;}return 1; } int main(){while (num<100…...

【PostgreSQL案例】我要查的表没有在执行计划中
问题:查的表没有在执行计划中 sql: SELECT* FROM(SELECTA.column1 as "column1",--中间省略很多A字段A.column99 as "column99"fromtable_a Aleft join (SELECTlzl_idfromtable_a AAinner join table_b BB ON AA.lzl_key BB.lzl_…...

《程序猿入职必会(5) · CURD 页面细节规范 》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...