Netty - NIO基础学习
一 简介
1 三大模型是什么?
IO三大模型之一,BIO,AIO,还有我们的主角NIO(non-blocking-io),也就是同步非阻塞式IO。这三种模型到底是干什么的?其实这三种模型都是对于JAVA的一种I/O框架,用来进行输入,输出操作。另一方面,以上三种模型提供的是统一的API操作,可以理解为JAVA针对于各种操作系统的IO模型进行的封装,从而具有一定的跨平台性等。作为开发者,我们不需要再了解有关操作系统层面的知识,直接使用这三种框架封装的API进行使用即可!
2 NIO
NIO(New Input/Output)是Java中的一种I/O(输入/输出)框架,主要用于处理异步I/O操作。它在Java 1.4版本中引入,旨在提高I/O操作的性能和可扩展性。
NIO的主要特点:
-
非阻塞I/O:NIO允许线程在发起I/O操作后继续执行其他任务,而不必等待I/O操作完成,从而提高了应用的响应性。
-
选择器(Selector):NIO引入了选择器,允许单个线程管理多个通道(Channel),从而减少了资源消耗和上下文切换的开销。
-
通道(Channel):NIO使用通道进行数据的读写,通道是双向的,可以同时进行读和写操作。
-
缓冲区(Buffer):NIO使用缓冲区来存储数据,缓冲区在读写过程中充当数据的临时存储区。
-
文件通道(FileChannel):NIO还提供了文件通道,可以用于高效地处理文件I/O。
NIO特别适合于需要处理大量并发连接的网络应用,如Web服务器和聊天应用等。通过非阻塞I/O和选择器,NIO能够更好地利用系统资源,提高整体性能。
二 NIO三大组件
1.Channel(通道)
相当于我们之前学习IO流操作中的输入输出流,起到一个通道的作用。但是在这里这个更加全面,既可以充当输入流,又可以充当输出流。是为双向通道。channel比Stream更底层,双向。
2.Buffer(缓冲区)
缓冲区,作为一个在网络或者是本地文件与计算机之间的桥梁,任何数据在进入通道Channel之前都需要经过Buffer。前者可以将数据读入Buffer,也可以将Buffer当中的数据写入Channel当中
3.Selector(选择器)
选择器是NIO中用于处理非阻塞I/O的核心组件。它允许单个线程管理多个通道。
我认为将其与各种服务器设计模式相结合进行介绍,会更加清晰。
我们以BIO(同步阻塞IO)举例,这样更加方便理解
我们都知道,BIO是一种同步阻塞IO,在服务端与客户端之间,其会建立一个一个通道(Socket)以进行彼此之间的数据输入和输出,但是对于一个服务端,如果想要与多个客户端之间建立连接,那么就需要建立多个线程,也就是一个线程对应一个客户端。如下图:

但是这样存在很大的弊端,如果有很多的客户端都进行访问,那么就会创建多个线程与其连接,就会导致CPU资源被占用许多,甚至直接宕机,导致客户端无法被外部访问。各个线程上下文之间的来回切换,线程创建,也会消耗大量资源。(这也就是为什么要创建线程池了。。。。)另一方面,BIO还有一个特点,那就是阻塞!如果一个客户端没有发送消息,那么对应的线程就会一直等待,直到客户端发送新的消息,才会继续进行执行。在此之前,等待的过程,就会造成CPU资源的大量占用。所以这种方式只适用于比较少的客户端访问。其实这就是服务器的设计之一 ----- 多线程设计模式
有的大佬就会想到,可以创建线程池来处理问题,没错,我们上面面对的一个大问题就是:线程会随着客户端的访问而不断的创建。从而导致资源的大量占用。使用线程池可以设定线程的最大数量,用以解决客户端访问过多造成的问题。但是这种解决方式也存在很大问题,至于为什么,大家可以想一想。
线程池设计模式。顾名思义,就是针对之前一个线程对应一个客户端的情形进行该进,变为一个线程针对多个客户端进行处理,如下:

这种设计模式相比多线程有所提高,但是因为在阻塞模式下,依旧是一个线程在处理时仅仅只能够处理一个客户端,也就是Socket连接,因此其适合一个线程下连接的Scoket比较少的情况。
Slector版设计模式。selector 的作用就是配合一个线程来管理多个 channel,获取这些 channel 上发生的事件,这些 channel 工作在非阻塞模式下,不会让线程吊死在一个 channel 上。适合连接数特别多,但流量低的场景(low traffic),如下图:

这种设计模式,一个线程对应一个选择器,这个选择器会直接监视其下的所有通道,一旦这些通道有什么动作发生,选择器就会将其汇报给线程,由线程进行解决。
非阻塞的形式,也就是说,我们选择器监视下的各个通道,比如第一个通道,如果其当前没有任务,那么我们的选择器就不会等待,而是直接看下一个通道是否有任务。
适合流量比较低,指的就是,如果我们的通道一下接收一个比较大的数据,那么选择器就会长时间的停留于它,直到它的任务结束,数据如果比较大,也就是如果流量比较大,那么就会影响其他通道的正常使用,因此适用于流量比较低的场景。
由此可见,选择器适合于事件驱动的应用程序,可以有效地处理大量并发连接,减少线程上下文切换的开销。
三 Buffer - ByteBuffer
上面我们简单说了几个比较缓冲区的Buffer,但是比较常用的实际上就一个ByteBuffer,所以我们拿这个作为详细介绍
1.基本使用
@Slf4j
public class ChannelDemo1 {public static void main(String[] args) {try (RandomAccessFile file = new RandomAccessFile("helloword/data.txt", "rw")) {FileChannel channel = file.getChannel();ByteBuffer buffer = ByteBuffer.allocate(10);do {// 向 buffer 写入int len = channel.read(buffer);log.debug("读到字节数:{}", len);if (len == -1) {break;}// 切换 buffer 读模式buffer.flip();while(buffer.hasRemaining()) {log.debug("{}", (char)buffer.get());}// 切换 buffer 写模式buffer.clear();} while (true);} catch (IOException e) {e.printStackTrace();}}
}
以上使用通道FileChannel与Buffer进行了一个简单的文件读取,以及对应文件内容的日志打印。
2.BetyBuffer使用说明:
-
向 buffer 写入数据,例如调用 channel.read(buffer)
-
调用 flip() 切换至读模式
-
从 buffer 读取数据,例如调用 buffer.get()
-
调用 clear() 或 compact() 切换至写模式
-
重复 1~4 步骤
3.ByteBuffer结构
其内部实际上是一个类似数组的存储结构,数组的长度也就是我们在使用allocate方法的时候自定义的。
ByteBuffer主要有三个比较重要的属性:
position(当前位置)
limit(限制)
capaciy(为数组容量)
刚开始写入数据操作
在我们刚开始进行数据写入操作的时候,position从头开始,后两个都在最后,每写入一个数据,对应的position指针就会向后移动一位,如图。

获取数据
使用filp获取数据的时候,对应的position指针就会从头开始,索引归零,取而代之的是limit,用来代替之前写入的数据的最大索引位置,为了防止读取出来的数据为空。

clear动作发生之后,会将数组内部的所有元素都清空,变为空,从头来过,重新进行写操作。

还有一种写操作,为compact动作,比如我们因为某种原因,之前没有读取完的数据,那么就会直接将其进向前压缩,并且更新对应读取的时候的Position以及Limit的位置。从而达到写的操作。

相关文章:
Netty - NIO基础学习
一 简介 1 三大模型是什么? IO三大模型之一,BIO,AIO,还有我们的主角NIO(non-blocking-io),也就是同步非阻塞式IO。这三种模型到底是干什么的?其实这三种模型都是对于JAVA的一种I/O框架,用来进行…...
ArrayList的自动扩容机制源码
Java的ArrayList的自动扩容机制 ArrayList是 Java 中极为常用的动态数组实现类,它依托数组存储数据,能依据实际需求灵活变动容量,高效管理元素集合。在深挖底层源码细节前,先来了解创建ArrayList集合并添加元素时的运作流程&#…...
【llm_inference】react框架(最小code实现)
ReAct:结合推理和行动的大语言模型推理架构 GitHub Code: 人人都能看懂的最小实现 引言 在人工智能领域,大语言模型(LLM)的应用日益广泛,但如何让模型能够像人类一样,在思考的基础上采取行动,…...
PT8M2103 触控 I/O 型 8-Bit MCU
1 产品概述 ● PT8M2103 是一款可多次编程(MTP)I/O 型8位 MCU,其包括 2K*16bit MTP ROM、256*8bit SRAM、PWM、Touch 等功能,具有高性能精简指令集、低工作电压、低功耗特性且完全集成触控按键功能。为各种触控按键的应用,提供了一种简单而又…...
英语时态学习+名词副词形容词变形方式
开发出头不容易 不如跨界卷英语 英语中的16种时态是由四种时间(现在、过去、将来、过去将来)和四种体(一般、进行、完成、完成进行)组合而成的。以下是每种时态的详细说明和例句: 一般现在时 (Simple Present) 用法…...
浏览器解析页面流程
从输入一个url到页面解析完成的流程 1. 网络进程 1. 获取url 浏览器首先判断输入的url是否有http缓存,如果有则直接从http缓存中读取数据并显示。如果没有,则进行下一步。进行DNS解析,获取域名对应的IP地址。 2.下载html文件 浏览器根据I…...
图的遍历之DFS邻接矩阵法
本题要求实现一个函数,对给定的用邻接矩阵存储的无向无权图,以及一个顶点的编号v,打印以v为起点的一个深度优先搜索序列。 当搜索路径不唯一时,总是选取编号较小的邻接点。 本题保证输入的数据(顶点数量、起点的编号等…...
Java --- JVM编译运行过程
目录 一.Java编译与执行流程: 二.编译过程: 1.编译器(javac): 2.字节码文件(.class): 三.执行过程: 1.启动JVM(Java虚拟机): 2…...
HTML5 拖拽 API 深度解析
一、HTML5 拖拽 API 深度解析 1.1 背景与发展 HTML5 的拖拽 API 是为了解决传统拖拽操作复杂而设计的。传统方法依赖鼠标事件和复杂的逻辑计算,而 HTML5 提供了标准化的拖拽事件和数据传递机制,使得开发者能够快速实现从一个元素拖拽到另一个元素的交互…...
GO--基于令牌桶和漏桶的限流策略
至于为什么要限流,字面意思已经很清楚了,就是为了减轻服务器的压力 下面我们将介绍两个限流策略----漏桶和令牌桶。 漏桶 原理介绍 漏桶,顾名思义就是一个漏斗,漏斗嘴的大小是固定的,所以不管漏斗现容量多大&#…...
MongoDB性能监控工具
mongostat mongostat是MongoDB自带的监控工具,其可以提供数据库节点或者整个集群当前的状态视图。该功能的设计非常类似于Linux系统中的vmstat命令,可以呈现出实时的状态变化。不同的是,mongostat所监视的对象是数据库进程。mongostat常用于…...
Axure设计之模拟地图人员移动轨迹
在产品原型设计时,为了更好的表达和呈现预期的效果,让客户或开发看一眼就能理解要实现的功能,往往需要在产品设计时尽量去接近现实,这就需要我们在使用Axure制作原型时应具有高度细节和逼真度的原型设计。原型设计不仅包含了产品的…...
Android环境搭建
Android环境搭建 第一步:安装 Homebrew 执行以下命令来安装 Homebrew: /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"检测是否安装成功: brew --version第二步:安装 No…...
前端工程化面试题(一)
如何使用 Docker 部署前端项目? 使用 Docker 部署前端项目通常涉及以下几个步骤: 创建项目:首先,需要在本地创建并配置好前端项目。 准备 Docker 文件: .dockerignore:这个文件用于排除不需要上传到 Dock…...
模型案例:| 手机识别模型!
导读 2023年以ChatGPT为代表的大语言模型横空出世,它的出现标志着自然语言处理领域取得了重大突破。它在文本生成、对话系统和语言理解等方面展现出了强大的能力,为人工智能技术的发展开辟了新的可能性。同时,人工智能技术正在进入各种应用领…...
期权懂|个股期权交割操作流程是什么样的?
期权小懂每日分享期权知识,帮助期权新手及时有效地掌握即市趋势与新资讯! 个股期权交割操作流程是什么样的? 一、行权申报: 期权买方在行权日通过其经纪商提交行权指令,表明其决定行使期权权利。 二、行权匹配…...
【openGauss】openGauss execute执行update语句,获取更新的行数
【openGauss】openGauss execute执行update语句,获取更新的行数 在openGauss中,可以使用execute语句执行update语句,并通过GET DIAGNOSTICS语句获取更新的行数。下面是一个示例: DO $$ DECLAREupdated_rows INTEGER; BEGINEXECUT…...
P8780 [蓝桥杯 2022 省 B] 刷题统计
题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 𝑎道题目,周六和周日每天做 𝑏 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 𝑛 题? 输入格式 输入一行包含三…...
切比雪夫不等式:方差约束下的概率估计
切比雪夫不等式:方差约束下的概率估计 背景 在概率分析中,切比雪夫不等式是一个常用的工具,它通过引入随机变量的 方差信息,给出了偏离均值的概率界限。这一不等式是对 马尔科夫不等式 的自然扩展,结合了更丰富的分布…...
使用CancellationTokenSource来控制长时间sql查询中断
前端 <!-- 透明的覆盖层,显示在页面上方,包含进度条 --><Grid Visibility"{Binding IsLoading}" Background"Transparent" HorizontalAlignment"Stretch" VerticalAlignment"Stretch" ZIndex"1&…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
