JAVA网络编程——BIO、NIO、AIO深度解析
I/O 一直是很多Java同学难以理解的一个知识点,这篇帖子将会从底层原理上带你理解I/O,让你看清I/O相关问题的本质。
1、I/O的概念
I/O 的全称是Input/Output。虽常谈及I/O,但想必你也一时不能给出一个完整的定义。搜索了谷哥欠,发现也尽是些冗长的论述。要想厘清I/O这个概念,我们需要从不同的视角去理解它。
1.1、计算机结构的视角
根据冯.诺依曼结构,计算机结构分为 5 大部分:运算器、控制器、存储器、输入设备、输出设备。其中输入是指将数据输入到计算机的设备,比如键盘鼠标;输出是指从计算机中获取数据的设备,比如显示器;以及既是输入又是输出设备,硬盘,网卡等。

用户通过操作系统才能完成对计算机的操作。计算机启动时,第一个启动的程序是操作系统的内核,它将负责计算机的资源管理和进程的调度。换句话说:操作系统负责从输入设备读取数据并将数据写入到输出设备。
1.2、程序应用的视角
根据大学里学到的操作系统相关的知识:为了保证操作系统的稳定性和安全性,一个进程的地址空间划分为 用户空间(User space) 和 内核空间(Kernel space ) 。
应用程序作为一个文件保存在磁盘中,只有加载到内存到成为一个进程才能运行。应用程序运行在计算机内存中,必然会涉及到数据交换,比如读写磁盘文件,访问数据库,调用远程API等等。但我们编写的程序并不能像操作系统内核一样直接进行I/O操作。
从应用程序的视角来看的话,我们的应用程序对操作系统的内核发起 IO 调用(系统调用),操作系统负责的内核执行具体的 IO 操作。也就是说,我们的应用程序实际上只是发起了 IO 操作的调用而已,具体 IO 的执行是由操作系统的内核来完成的。
但操作系统向外提供API,其由各种类型的系统调用(System Call)组成,以提供安全的访问控制。所以应用程序要想访问内核管理的I/O,必须通过调用内核提供的系统调用(system call)进行间接访问。
所以I/O之于应用程序来说,强调的通过向内核发起系统调用完成对I/O的间接访问。换句话说应用程序发起的一次IO操作实际包含两个阶段:
- IO调用阶段:应用程序进程向内核发起系统调用。
- IO执行阶段:内核执行IO操作并返回。准备数据阶段:内核等待I/O设备准备好数据;拷贝数据阶段:将数据从内核缓冲区拷贝到用户空间缓冲区。
UNIX 系统下, IO 模型一共有 5 种:
- 同步阻塞 I/O、
- 同步非阻塞 I/O、
- I/O 多路复用、
- 信号驱动 I/O
- 异步 I/O。
推荐孙卫琴老师的书籍:

2、BIO (Blocking I/O)
应用程序中进程在发起IO调用后至内核执行IO操作返回结果之前,若发起系统调用的线程一直处于等待状态,则此次IO操作为阻塞IO。阻塞IO简称BIO,Blocking IO。其处理流程如下图所示:

从上图可知当用户进程发起IO系统调用后,内核从准备数据到拷贝数据到用户空间的两个阶段期间用户调用线程选择阻塞等待数据返回。
因此BIO带来了一个问题:如果内核数据需要耗时很久才能准备好,那么用户进程将被阻塞,浪费性能。为了提升应用的性能,虽然可以通过多线程来提升性能,但线程的创建依然会借助系统调用,同时多线程会导致频繁的线程上下文的切换,同样会影响性能。所以要想解决BIO带来的问题,我们就得看到问题的本质,那就是阻塞二字。
3、NIO (Non-blocking/New I/O)
Java NIO 全称 Java non-blocking IO,是指 JDK 提供的新 API。从 JDK1.4 开始,Java 提供了一系列改进的输入/输出的新特性,被统称为 NIO(即 NewIO),是同步非阻塞的。
那解决方案自然也容易想到,将阻塞变为非阻塞,那就是用户进程在发起系统调用时指定为非阻塞,内核接收到请求后,就会立即返回,然后用户进程通过轮询的方式来拉取处理结果。也就是如下图所示:

应用程序中进程在发起IO调用后至内核执行IO操作返回结果之前,若发起系统调用的线程不会等待而是立即返回,则此次IO操作为非阻塞IO模型。非阻塞IO简称NIO,Non-Blocking IO。
然而,非阻塞IO虽然相对于阻塞IO大幅提升了性能,但依旧不是完美的解决方案,其依然存在性能问题,也就是频繁的轮询导致频繁的系统调用,会耗费大量的CPU资源。比如当并发很高时,假设有1000个并发,那么单位时间循环内将会有1000次系统调用去轮询执行结果,而实际上可能只有2个请求结果执行完毕,这就会有998次无效的系统调用,造成严重的性能浪费。有问题就要解决,那NIO问题的本质就是频繁轮询导致的无效系统调用。
3、AIO (Non-blocking/New I/O)
AIO 也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型。
异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。

目前来说 AIO 的应用还不是很广泛。Netty 之前也尝试使用过 AIO,不过又放弃了。这是因为,Netty 使用了 AIO 之后,在 Linux 系统上的性能并没有多少提升。
4、总结
I/O 其关键点是要将应用程序的IO操作分为两个步骤来理解:IO调用和IO执行。IO调用才是应用程序干的事情,而IO执行是操作系统的工作。在IO调用时,对待操作系统IO就绪状态的不同方式,决定了其是阻塞或非阻塞模式;在IO执行时,线程或进程是否挂起等待IO执行决定了其是否为同步或异步IO。
相关文章:
JAVA网络编程——BIO、NIO、AIO深度解析
I/O 一直是很多Java同学难以理解的一个知识点,这篇帖子将会从底层原理上带你理解I/O,让你看清I/O相关问题的本质。 1、I/O的概念 I/O 的全称是Input/Output。虽常谈及I/O,但想必你也一时不能给出一个完整的定义。搜索了谷哥欠,发…...
Linux高级系统编程-3 进程
概念 进程与程序的区别 程序:一个可执行文件, 占磁盘空间,是静态的 进程:一个程序运行的过程, 占内存,动态的。 单道程序和多道程序 单道程序设计: 所有进程一个一个排队执行。若 A 阻塞, B 只能等待࿰…...
ES-ELSER 如何在内网中离线导入ES官方的稀疏向量模型(国内网络环境下操作方法)
ES官方训练了稀疏向量模型,用来支持语义检索。(目前该模型只支持英文) 最好是以离线的方式安装。在线的方式,在国内下载也麻烦,下载速度也慢。还不如用离线的方式。对于一般的生产环境,基本上也是网络隔离的…...
Excel 使用技巧
Excel 使用技巧 注意: excel 中设计计算的字符尽量使用英文。 拼接两段文字(字符串拼接) 方法一 在需要计算的单元格上,键入 点击 A1(点击需要拼接的单元格) & C1(点击需要拼接的单元格) 举例: 姓名栏想要拼接 姓 和 名 两列点击姓名这一…...
Hadoop学习笔记(HDP)-Part.03 资源规划
目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …...
一个最新国内可用的免费GPT4,Midjourney绘画网站+使用教程
一、前言 ChatGPT GPT4.0,Midjourney绘画,相信对大家应该不感到陌生吧?简单来说,GPT-4技术比之前的GPT-3.5相对来说更加智能,会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而,GPT-4对普…...
深入了解Java8新特性-日期时间API之ZonedDateTime类
阅读建议 嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议: 本篇文章大概19000多字,预计阅读时间长需要10分钟以上。本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章&…...
使用Vue写一个日期选择器
在 Vue 中实现日期选择器的方法有很多,下面提供一个简单的实现方法。 首先,在需要使用日期选择器的组件中引用 Vue 和 date-fns 库,date-fns 库是一个轻量级的 JavaScript 时间日期工具库,可以方便地处理日期的格式化和计算。 &…...
19、pytest通过mark标记测试函数
官方实例 [pytest] markers slow:marks tests as slow(deselect with -m "not slow")serial# content of test_mark.py import pytestpytest.mark.slow def test_mark_function():print("test_mark_function was invoked")assert 0解读与实操 通过使用p…...
Linux环境变量与命令行参数
Linux环境变量与命令行参数 一.命令行参数1.语法2.应用1:简易计算器 二.环境变量1.环境变量的概念2.环境变量的作用3.进一步理解环境变量的作用4.常见环境变量5.导出环境变量(添加环境变量)6.环境变量的特性7.另一种获取环境变量的方式8.小功能:用于身份验证的代码9.补充:第三种…...
jQuery实现3D轮播图
通过CSS3的3D变换和jQuery Transit插件实现了一个3D旋转的图片轮播效果 HTML部分: div id“banner”:定义了一个id为"banner"的div标签,作为图片轮播的容器。 ul: 在"banner"中定义了一个无序列表,每个列表项…...
Java面试题(每天10题)-------连载(43)
目录 Spring篇 1、请举例说明Qualifier注解 2、构造方法注入和设值注入有什么区别? 3、Spring框架中有哪些不同类型的事件? 4、FileSystemResource和ClassPathResource有什么区别? 5、Spring框架中都用到了哪些设计模式? 6…...
Python高级数据结构——并查集(Disjoint Set)
Python中的并查集(Disjoint Set):高级数据结构解析 并查集是一种用于处理集合的数据结构,它主要支持两种操作:合并两个集合和查找一个元素所属的集合。在本文中,我们将深入讲解Python中的并查集࿰…...
pytorch学习9-优化器学习
系列文章目录 pytorch学习1-数据加载以及Tensorboard可视化工具pytorch学习2-Transforms主要方法使用pytorch学习3-torchvisin和Dataloader的使用pytorch学习4-简易卷积实现pytorch学习5-最大池化层的使用pytorch学习6-非线性变换(ReLU和sigmoid)pytorc…...
MySQL之锁
MySQL之锁 锁是计算机在执行多线程或线程时用于并发访问同一共享资源时的同步机制,MySQL中的锁是在服务器层或者存储引擎层实现的,保证了数据访问的一致性与有效性 MySQL锁可以按模式分类为:乐观锁与悲观锁。 按粒度分可以分为全局锁、表级锁…...
今日现货黄金最新建议
近期现货黄金价格再度逼近历史高位,很多本来在场外观望的投资者,都纷纷希望进场一试身手。然而大涨大跌的行情并不是很适合新手投资者参与,如果大家还没做好技术上的准备,可以多听听正规交易平台的专业人士的意见。 在正式入市之前…...
基于混沌算法的图像加密解密系统
1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义: 随着信息技术的迅猛发展,图像的传输和存储已经成为现代社会中不可或缺的一部分。然而,随着互联网的普及和信息的快速传播&am…...
vscode插件离线下载
离线下载插件地址:https://marketplace.visualstudio.com/VSCode...
第二十一章总结
一、网络通信: 1.网络程序设计基础:网络程序设计编写的是与其他计算机进行通信的程序。 1.1局域网与互联网:为了实现两台计算机的通信,必须用一个网络线路连接两台计算机 2.网络协议:网络协议规定了计算机之间连接的…...
查看端口占用并杀死进程
1.安装查看工具 sudo yum install net-tools 2.查看占用情况 netstat -tunlp | grep 8089 3.杀死进程 kill -9 227...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
