当前位置: 首页 > news >正文

java 的三种IO模型(BIO、NIO、AIO)

java 的三种IO模型(BIO、NIO、AIO)

    • 一、BIO 阻塞式 IO(Blocking IO)
      • 1.1、BIO 工作机制
      • 1.2、BIO 实现单发单收
      • 1.3、BIO 实现多发多收
      • 1.4、BIO 实现客户端服务端多对一
      • 1.5、BIO 模式下的端口转发思想
    • 二、NIO 同步非阻塞式 IO(Non-blocking IO)
      • 2.1、NIO 3个核心组件(缓冲区、通道、选择器)
      • 2.2、NIO 主要特性
      • 2.3、NIO 与 BIO 的对比
      • 2.4、Buffer 常用子类
      • 2.5、Buffer 重要属性
    • 三、AIO 异步式 IO(Asynchronous IO)
      • 3.1、AIO 核心组件(异步通道、完成处理器)


一、BIO 阻塞式 IO(Blocking IO)

每个客户端连接都会在一个独立的线程中处理,并且这个线程在处理 IO 操作时会阻塞,直到操作完成。

  • 每个连接都需要一个独立的线程,连接数较多时,会消耗大量的内存和 CPU 资源
  • 线程在处理 IO 操作时会阻塞

1.1、BIO 工作机制

  • 客户端通过 Socket 对象与服务端建立连接,从 Socket 中得到字节输入流或输出流进行数据读写。
  • 服务端通过 ServerSocket 注册端口,调用 accept 方法监听客户端 Socket 请求,从 Socket 中得到字节输入流或输出流进行数据读写。

1.2、BIO 实现单发单收

客户端:

public static void main(String[] args) {Socket socket = null;try {//与服务端连接socket = new Socket("127.0.0.1", 5000);//从 socket 管道中获取字节输出流OutputStream os = socket.getOutputStream();//将字节输出流包装为打印流PrintStream ps = new PrintStream(os);//发一行数据ps.println("Hi BIO! 与服务端通信成功");ps.flush();} catch (IOException e) {e.printStackTrace();}
}

服务端:

 public static void main(String[] args) {System.out.println("===服务端启动===");ServerSocket serverSocket = null;try {//注册端口serverSocket = new ServerSocket(5000);//监听客户端请求Socket socket = serverSocket.accept();//从 socket 管道中获取字节输入流InputStream is = socket.getInputStream();//将字节输入流包装为缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));String msg;//读一行数据if ((msg = br.readLine()) != null) {System.out.println("服务端接收客户端信息为:" + msg);}}catch (Exception e){System.out.println(e.getMessage());}
}

1.3、BIO 实现多发多收

客户端:

public static void main(String[] args) {try {Socket socket = new Socket("localhost",9988);OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);Scanner scanner = new Scanner(System.in);while (true){System.out.println("请输入:");String input = scanner.nextLine();ps.println(input);ps.flush();}} catch (IOException e) {e.printStackTrace();}
}

服务端:

public static void main(String[] args) {System.out.println("===服务端启动===");try {ServerSocket ss = new ServerSocket(9988);Socket socket = ss.accept();InputStream is = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));String message;while ((message = br.readLine()) != null){System.out.println("服务端接收客户端信息为:" + message);}} catch (IOException e) {e.printStackTrace();}
}

1.4、BIO 实现客户端服务端多对一

服务端:

public void listen() throws IOException {ServerSocket serverSocket = null;try {log.info("服务启动监听");serverSocket = new ServerSocket(9988);//循环接收到客户端的连接while (true) {Socket socket = serverSocket.accept();//得到连接后,开启一个线程处理连接handleSocket(socket);}} finally {if(serverSocket != null){serverSocket.close();}}
}private void handleSocket(Socket socket) {HandleSocket socketHandle = new HandleSocket(socket);new Thread(socketHandle).start();
}
public void run() {BufferedInputStream bufferedInputStream = null;BufferedOutputStream bufferedOutputStream  = null;try {bufferedInputStream = new BufferedInputStream(socket.getInputStream());byte[] bytes = new byte[1024];int len ;if ((len = bufferedInputStream.read(bytes)) > -1) {String result = new String(bytes,0,len);System.out.println("本次接收到的结果:" + result);}System.out.println("回复信息给客户端:");bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());String outString = Thread.currentThread().getName() + "接收到了";bufferedOutputStream.write(outString.getBytes());bufferedOutputStream.flush();} catch (IOException e) {System.out.println("处理异常:" + e.getMessage());} finally {try {if (bufferedInputStream != null) {bufferedInputStream.close();}if (bufferedOutputStream != null) {bufferedOutputStream.close();}}catch (IOException e){System.out.println("关闭流异常:" + e.getMessage());}}
}

客户端:

public void start() throws IOException {Socket socket = new Socket("127.0.0.1", 8081);String msg = "Hi,This is the BioClient";BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());byte[] bytes = msg.getBytes();bufferedOutputStream.write(bytes);bufferedOutputStream.flush();System.out.println("发送完毕");BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());byte[] inBytes = new byte[1024];int len;if ((len = bufferedInputStream.read(inBytes)) != -1) {String result = new String(inBytes, 0, len);System.out.println("接收到的消息="+result);}bufferedOutputStream.close();bufferedInputStream.close();socket.close();
}

1.5、BIO 模式下的端口转发思想

一个客户端的消息经由服务端发送给所有的客户端,实现群聊功能。
在这里插入图片描述

public class Server {// 定义一个静态集合public static List<Socket> allSocketOnLine = new ArrayList();public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(9999);while (true){Socket socket = ss.accept();// 把登录的客户端socket存入到一个在线的集合中去allSocketOnLine.add(socket);// 为当前登录成功的socket分配一个独立的线程来处理new ServerReaderThread(socket).start();}} catch (IOException e) {e.printStackTrace();}}}public class ServerReaderThread extends Thread{private Socket socket;public ServerReaderThread(Socket socket){this.socket = socket;}@Overridepublic void run() {try {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg;while ((msg = br.readLine()) != null) {// 发送给所有的在线socketsendMsgToAllClient(msg);}} catch (Exception e) {System.out.println("有人下线了");Server.allSocketOnLine.remove(socket);}}/*** 把当前客户端发来的消息发送给全部的在线socket* @param msg*/private void sendMsgToAllClient(String msg) throws IOException {for (Socket sk : Server.allSocketOnLine) {PrintWriter pw = new PrintWriter(sk.getOutputStream());pw.println(msg);pw.flush();}}}

二、NIO 同步非阻塞式 IO(Non-blocking IO)

允许线程在等待IO操作完成期间可以继续执行其他任务。

2.1、NIO 3个核心组件(缓冲区、通道、选择器)

缓冲区(Buffer):用于存储数据的对象。数据从通道读取到缓冲区,或者从缓冲区写入到通道。

通道(Channel):既可以从通道中读取数据,又可以写数据到通道

选择器(Selector):同时管理多个通道,通过注册通道的事件(如连接就绪、读就绪、写就绪),使用单个线程就能处理多个通道,从而管理多个网络连接,提高了效率。
在这里插入图片描述

2.2、NIO 主要特性

  • 非阻塞I/O:允许线程在等待IO操作完成期间可以继续执行其他任务
  • IO多路复用:通过选择器,NIO允许多个通道共用一个线程进行管理,减少了线程的资源消耗。
  • 异步IO操作:可以在通道上注册事件和回调函数,实现非阻塞的IO操作
  • 内存映射文件:将文件的一部分或全部直接映射到内存中,这样可以像访问内存一样访问文件,提高了文件处理的效率。
  • 文件锁定:允许对文件的部分或全部进行锁定,从而控制对文件的并发访问。

2.3、NIO 与 BIO 的对比

  • 面向流与面向缓冲:BIO 是面向流的,每次从流中读一个或多个字节,直至读取所有字节;而 NIO 是面向缓冲区的。
  • 阻塞与非阻塞:BIO 的流是阻塞的,当一个线程调用 read()write() 时,该线程被阻塞,直到有一些数据被读取或数据完全写入;而 NIO 是非阻塞的,一个线程从某通道发送请求读取数据,它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。
  • 线程开销:BIO 为每个客户端连接创建一个线程,在大量并发连接的情况下会带来巨大的线程开销;NIO 通过选择器实现 I/O多路复用,在一个线程中处理多个通道,减少了线程开销。

2.4、Buffer 常用子类

  • ByteBuffer:用于存储字节数据;
  • CharBuffer:用于存储字符数据;
  • ShortBuffer:用于存储Short类型数据;
  • IntBuffer:用于存储Int类型数据;
  • LongBuffer:用于存储Long类型数据;
  • FloatBuffer:用于存储Float类型数据;
  • DoubleBuffer:用于存储Double类型数据;

2.5、Buffer 重要属性

  • capacity(容量):表示 Buffer 所占的内存大小,不能为负且创建后不能更改
  • limit(限制):表示 Buffer 中可以操作数据的大小,不能为负且不能大于 capacity
    写模式下,表示最多能往 Buffer 里写多少数据,即 limit 等于 capacity
    读模式下,表示最多能读到多少数据,即已写入的所有数据
  • position(位置):表示下一个要读取或写入的数据的索引
    缓冲区位置不能为负,且不能大于其限制
    初始 position 值为 0,最大为 capacity – 1。当一个 byte、long 等数据写到 Buffer 后, position 会向前移动到下一个可插入数据的 Buffer 单元
  • mark(标记):表示记录当前 position 的位置,可通过 reset() 恢复到 mark 的位置

三、AIO 异步式 IO(Asynchronous IO)

异步式IO操作不会阻塞线程,而是交由操作系统处理。完成后,操作系统会通知应用程序,或者应用程序主动查询完成状态。使线程在等待IO完成的同时可以执行其他任务,提高了系统的并发性能。

3.1、AIO 核心组件(异步通道、完成处理器)

  1. 异步通道(Asynchronous Channel):AIO 中进行I/O操作的基础设施。
    AIO提供了多种异步通道:
    AsynchronousSocketChannel(异步套接字通道,支持面向连接的网络通信)AsynchronousServerSocketChannel(异步服务器套接字通道,支持异步服务器端套接字通信)AsynchronousFileChannel(异步文件通道,支持异步文件读写操作)

  2. 完成处理器(Completion Handler):用于在I/O操作完成后处理结果的回调接口。
    完成处理器包含两个方法:
    completed(V result, A attachment) 在I/O操作成功完成时调用;
    failed(Throwable exc, A attachment) 在I/O操作失败时调用。

相关文章:

java 的三种IO模型(BIO、NIO、AIO)

java 的三种IO模型&#xff08;BIO、NIO、AIO&#xff09; 一、BIO 阻塞式 IO&#xff08;Blocking IO&#xff09;1.1、BIO 工作机制1.2、BIO 实现单发单收1.3、BIO 实现多发多收1.4、BIO 实现客户端服务端多对一1.5、BIO 模式下的端口转发思想 二、NIO 同步非阻塞式 IO&#…...

低级语言和高级语言、大小写敏感、静态语言和动态语言、链接

低级语言和高级语言 一般而言&#xff0c;更接近硬件的语言被称为低级语言&#xff0c;反之&#xff0c;更远离硬件被称为高级语言。C语言既有低级语言的特点&#xff0c;又有高级语言的特点&#xff0c;又被称为系统语言。Java/Python一般被称为高级语言。 大小写敏感 DOS/Win…...

P3197 [HNOI2008] 越狱

题目传送门 题面 [HNOI2008] 越狱 题目描述 监狱有 n n n 个房间&#xff0c;每个房间关押一个犯人&#xff0c;有 m m m 种宗教&#xff0c;每个犯人会信仰其中一种。如果相邻房间的犯人的宗教相同&#xff0c;就可能发生越狱&#xff0c;求有多少种状态可能发生越狱。 …...

会声会影导出视频mp4格式哪个最高清,会声会影输出格式哪个清晰

调高分辨率后&#xff0c;mp4视频还是不清晰。哪怕全部使用4K级素材&#xff0c;仍然剪不出理想中的高画质作品。不是你的操作有问题&#xff0c;而是剪辑软件没选对。Corel公司拥有全球顶尖的图像处理技术&#xff0c;该公司研发的会声会影视频剪辑软件&#xff0c;在过去的20…...

Linux:进程调度算法和进程地址空间

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一 进程调度算法 1.1 进程队列数据结构 1.2 优先级 ​编辑 1.3 活动队列 ​编辑 1.4 过期队列 1.5 active指针和expired指针 1.6 进程连接 二 进程地址空间 2.1 …...

TCP ---滑动窗口以及拥塞窗口

序言 在上一篇文章中我们介绍了 TCP 中的协议段格式&#xff0c;以及保证其可靠传输的重传机制&#xff0c;着重介绍了三次握手建立连接&#xff0c;四次挥手断开连接的过程(&#x1f449;点击查看)。  这只是 TCP 保证通信可信策略的一部分&#xff0c;现在让我们继续深入吧&…...

第十二章--- fixed 和 setprecision 函数、round 函数、进制转换及底层逻辑

1. 保留几位小数 在C中&#xff0c;如果你想要控制输出的小数点后的位数&#xff0c;可以使用<iomanip>头文件提供的fixed和setprecision函数。这里的fixed用于设置浮点数的输出格式为定点表示法&#xff0c;而setprecision(n)则用来指定小数点后保留的位数。具体用法如…...

ASP.NetCore---I18n(internationalization)多语言版本的应用

文章目录 0.实现的效果如下1.创建新项目I18nBaseDemo2.添加页面中的下拉框3.在HomeController中添加ChangeLanguage方法4.在Progress.cs 文件中添加如下代码&#xff1a;5. 在progress.cs中添加code6.添加Resource资源文件7.在页面中引用i18n的变量8. 重启项目&#xff0c;应该…...

vue3 环境配置vue-i8n国际化

一.依赖和插件的安装 主要是vue-i18n和 vscode的自动化插件i18n Ally https://vue-i18n.intlify.dev/ npm install vue-i18n10 pnpm add vue-i18n10 yarn add vue-i18n10 vscode在应用商城中搜索i18n Ally&#xff1a;如图 二.实操 安装完以后在对应项目中的跟package.jso…...

2024 uniapp入门教程 01:含有vue3基础 我的第一个uniapp页面

uni-app官网uni-app,uniCloud,serverless,快速体验,看视频&#xff0c;10分钟了解uni-app,为什么要选择uni-app&#xff1f;,功能框架图,一套代码&#xff0c;运行到多个平台https://uniapp.dcloud.net.cn/ 准备工作&#xff1a;HBuilder X 软件 HBuilder X 官网下载&#xf…...

CentOS 7文件系统

从centos7开始&#xff0c;默认的文件系统从ext4变成了XFS。随着虚拟化的应用越来越广泛&#xff0c;作为虚拟化磁盘来源的大文件&#xff08;单个文件几GB级别&#xff09;越来越常见。 1.XFS组成部分&#xff1a; XFS文件系统在数据的分布上主要划分为三部分&#xff1a;数据…...

vue源码解析(源码解析学习大纲)

文章目录 Vue源码解析入手方向大纲1.核心概念1-1.响应式系统1-2. 组件1-3. 虚拟DOM1-4. 指令1-5. 生命周期钩子 2.虚拟DOM2-1. 概念2-2. 工作流程2-3. 示例2-4.总结 3.组件系统3-1. 组件的定义3-2. 组件的创建3-3. 组件的模板3-4. 生命周期3-5. 事件处理3-6. 插槽&#xff08;S…...

工行企业网银U盾展期后有两个证书问题的解决方法

工行企业网银U盾证书快到期后&#xff0c;可以自助展期&#xff0c;流程可以根据企业网银提示页面操作。操作后&#xff0c;可能存在两个新旧两个证书并存的情况&#xff0c;致使网银转账等操作失败&#xff0c;如图&#xff1a; 其原因是新证书生成后&#xff0c;旧证书没有删…...

《Linux从小白到高手》理论篇:文件权限控制及文件操作相关的命令

List item 本篇介绍Linux文件权限控制及文件操作相关的命令&#xff0c;看完本文&#xff0c;有关Linux文件权限控制及文件操作相关的常用命令你就掌握了99%了。 文件权限 在介绍文件权限之前先来复习下Linux的文件类型&#xff0c;始终记住那句话&#xff1a;Linux系统下&a…...

前端框架React的详细的学习方法和过程

学习React作为前端架构的一部分&#xff0c;是一个系统且逐步深入的过程。以下是一个详细的学习方法和过程&#xff0c;可以帮助你有效地掌握React&#xff1a; 1. 理解React的基础知识 首先&#xff0c;你需要了解React的基本概念&#xff0c;包括它是什么、为什么使用它以及…...

linux中缓存,在kafka上应用总结

linux中的缓存 页缓存 pagecatch&#xff08;读缓存用于提供快速读&#xff09;块缓存&#xff08;用于提供其他设备快速写&#xff09;当对读缓存读的时候&#xff0c;修改了读的数据&#xff0c;页缓存就会被标记为脏数据&#xff0c;等到写的时候它会向块缓存同步数据&…...

前端练习小项目 —— 让图片变得更 “色”

前言&#xff1a;相信读者在学习完了HTML、CSS和JavaScript之后已经想要迫不及待的想找一个小型的项目来练练手&#xff0c;那么这篇文章就正好能满足你的 “需求”。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 在开始学习…...

时间卷积网络(TCN)原理+代码详解

目录 一、TCN原理1.1 因果卷积&#xff08;Causal Convolution&#xff09;1.2 扩张卷积&#xff08;Dilated Convolution&#xff09; 二、代码实现2.1 Chomp1d 模块2.2 TemporalBlock 模块2.3 TemporalConvNet 模块2.4 完整代码示例 参考文献 在理解 TCN 的原理之前&#xff…...

零散的知识

1.物化 在SQL中&#xff0c;物化&#xff08;Materialization&#xff09;是指将查询结果保存为物理数据结构以供后续使用的过程。这与普通的视图或查询不同&#xff0c;物化视图会存储查询的结果&#xff0c;而不是每次查询时都动态地重新计算数据。 ①物化视图 物化视图是一…...

Python读取pdf中的文字与表格

一、PyPDF2包安装 在Python中安装PyPDF2库&#xff0c;您可以使用pip包管理器。打开您的命令行工具&#xff08;例如CMD、Terminal或Anaconda Prompt&#xff09;&#xff0c;然后输入以下命令&#xff1a; pip install PyPDF2 如果您使用的是Python 3&#xff0c;并且系统中…...

【MySQL 08】复合查询

目录 1.准备工作 2.多表查询 笛卡尔积 多表查询案例 3. 自连接 4.子查询 1.单行子查询 2.多行子查询 3.多列子查询 4.在from子句中使用子查询 5.合并查询 1.union 2.union all 1.准备工作 如下三个表&#xff0c;将作为示例&#xff0c;理解复合查询 EMP员工表…...

求1000以内的完数

题目&#xff1a;一个数如果恰好等于他的因子之和&#xff08;包括1&#xff0c;但不包括这个数&#xff09;&#xff0c;这个数就是完数。编写算法找出1000之内的所有完数&#xff0c;并按下面格式输出其因子&#xff1a;28 its factors are 1,2,4,7,14 代码如下&#xff1a;…...

sqli-labs less-16 post提交dnslog注入

post提交DNSlog注入 第十六关和和十五关大差不大&#xff0c;可以使用布尔注入&#xff0c;时间盲注等&#xff0c;只不过闭合方式不一样&#xff0c;但是用布尔和时间盲太过于消耗时间&#xff0c;本次测试我将使用dnslog注入。 使用在线平台http://www.dnslog.cn/ 闭合方式…...

nginx报错|xquic|xqc_engine_create: fail|

一.问题描述 nginx使用xquic协议一切安装正常,nginx -s reload也正常&#xff0c;但就是访问不了网页 [emerg] 12342#0: |xquic|xqc_engine_create: fail| [emerg] 12342#0: |xquic|ngx_xquic_process_init|engine_init fail| [emerg] 12341#0: |xquic|xqc_engine_create: fai…...

Java虚拟机(JVM)

目录 内存区域划分堆&#xff08;Heap&#xff09;方法区&#xff08;Method Area&#xff09;程序计数器&#xff08;Program Counter Register&#xff09;虚拟机栈&#xff08;VM Stack&#xff09;本地方法栈&#xff08;Native Method Stack&#xff09; 类加载的过程类加…...

MQ 架构设计原理与消息中间件详解(三)

RabbitMQ实战解决方案 RabbitMQ死信队列 死信队列产生的背景 RabbitMQ死信队列俗称&#xff0c;备胎队列&#xff1b;消息中间件因为某种原因拒收该消息后&#xff0c;可以转移到死信队列中存放&#xff0c;死信队列也可以有交换机和路由key等。 产生死信队列的原因 消息投…...

大数据新视界 --大数据大厂之 Alluxio 数据缓存系统在大数据中的应用与配置

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

PHP基本语法总结

目录 输出语句 注释 数据类型&#xff08;变量&#xff09; 局部和全局作用域 类型比较&#xff08;松散比较与严格比较&#xff09; 常量 运算符 并置运算符 不等于 逻辑运算符 条件语句 数组 关联数组 数组排序 一般数组 关联数组 循环 函数 变量函数 魔…...

尚硅谷rabbitmq 2024第30-33节 死信队列 答疑

Virtual host: Type: Name: Durabiity: Arguments: Default for virtual host w ququt.normal.video Durable x-dead-letter-exchange x-dead-1etter-routing-xey x-mAx-1ength X-m在88点0也-6E1 exchange.dead.letter.vide zouting.key.dead.ietter.v 10 String String Number…...

解锁空间距离计算的多种方式-含前端、空间数据库、后端

目录 前言 一、空间数据库求解 1、PostGIS实现 二、GIS前端组件求解 1、Leaflet.js距离测算 2、Turf.js前端计算 三、后台距离计算生成 1、欧式距离 2、Haversice球面距离 3、GeoTools距离计算 4、Gdal距离生成 5、geodesy距离计算 四、成果与生成对比 1、Java不…...