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操作失败时调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/444250.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新款平行进口奔驰GLS450升级原厂AR实景导航人机交互行车记录仪等功能

平行进口的24款奔驰GLS450升级原厂中规导航主机通常具备以下功能&#xff1a; 人机交互系统&#xff1a;该导航主机配备了人机交互系统&#xff0c;可以通过触摸屏、旋钮或语音控制等方式与导航系统进行交互&#xff0c;方便驾驶者进行导航设置和操作。 实景AR导航&#xff1…

如何利用wsl-Ubuntu里conda用来给Windows的PyCharm开发

前提&#xff1a;咱们在wsl-Ubuntu上&#xff0c;有conda的虚拟环境 咱们直接打开PyCharm,打开Settings 更换Python Interpreter即可 当然一开始可能没有下面的选项&#xff0c;需要我们点击右边的Add Interpreter 这里选择wsl 点击next 将这两步进行修改 可以看出来&#xff0…

算法: 前缀和题目练习

文章目录 前缀和题目练习前缀和二维前缀和寻找数组的中心下标除自身以外数组的乘积和为 K 的子数组和可被 K 整除的子数组连续数组矩阵区域和 前缀和题目练习 前缀和 自己写出来了~ 坑: 数据太大,要用long. import java.util.Scanner;public class Main {public static voi…

【AIGC】寻找ChatGPT最佳推理步骤:CoT思维链技术的探索与应用

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;CoT思维链概述&#x1f4af;CoT思维链在大型语言模型中的应用&#x1f4af;CoT思维链改变对模型推理能力的理解和改进方式多样化应用场景挑战与未来发展总结 &#x1f4a…

网关在不同行业自动化生产线的应用

网关在不同行业自动化生产线的应用&#xff0c;展示了其作为信息与物理世界交汇点的广泛影响力&#xff0c;尤其在推动行业智能化、自动化方面发挥了不可估量的作用。以下是网关技术在污水处理、智慧农业、智慧工厂、电力改造及自动化控制等领域的深入应用剖析。 1. 污水处理 …

初级网络工程师之从入门到入狱(五)

本文是我在学习过程中记录学习的点点滴滴&#xff0c;目的是为了学完之后巩固一下顺便也和大家分享一下&#xff0c;日后忘记了也可以方便快速的复习。 网络工程师从入门到入狱 前言一、链路聚合1.1、手动进行链路聚合1.1.1、 拓扑图&#xff1a;1.1.2、 LSW11.1.3、 LSW2 1.2、…

智谱开放平台API调用解析

一、什么是智谱AI 智谱AI成立于2019年&#xff0c;由‌清华大学计算机系知识工程实验室的技术成果转化而来&#xff0c;是一家致力于人工智能技术研发和应用的公司。智谱致力于打造新一代认知智能大模型&#xff0c;专注于做大模型的中国创新。 二、智谱开放平台API调用 官方文…

十、kotlin的协程

协程 基本概念定义组成挂起和恢复结构化并发协程构建器作用域构建器挂起函数阻塞与非阻塞runBlocking全局协程像守护线程 Job的生命周期 常用函数延时和等待启动和取消启动取消 暂停 协程启动调度器启动方式启动模式线程上下文继承的定义继承的公式 协程取消与超时取消挂起点取…

计算机视觉之OpenCV vs YOLO

好多开发者希望搞明白OpenCV 和YOLO区别&#xff0c;实际上&#xff0c;二者在计算机视觉领域都有广泛应用&#xff0c;但它们有很大的不同。 一、OpenCV 概述 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它…

电磁兼容系列

1.1 电磁兼容基本概念 “电磁兼容是研究在有限空间、时间、频谱资源条件下&#xff0c;各种用电设备&#xff08;广义的还包括生物体&#xff09;可以共存&#xff0c;并不致引起降级的一门学科。“ 研究频率范围&#xff1a;0Hz~400GHz&#xff08;CISRP 24&#xff09;&…

vite学习教程05、vite+vue2构建本地 SVG 图标

文章目录 前言一、构建本地SVG图标详细步骤1、安装开发依赖2、配置vite2.1、配置vite.config.js2.2、封装vite引入插件脚本 解决报错&#xff1a;can not find package fast-glob imported 二、实际应用应用1&#xff1a;未封装&#xff0c;直接vue应用应用2&#xff1a;封装vu…

RTSP 音视频play同步分析

基础理论 RTSP RTP RTCP SDP基础知识-CSDN博客 关于RTP的时间戳知识点回顾 时间戳单位&#xff1a;时间戳计算的单位不是秒&#xff0c;而是采用采样频率的倒数&#xff0c;这样做的目的是为了使时间戳单位更为精准。比如说一个音频的采样频率为8000Hz&#xff0c;那么我们可…

J1学习打卡

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 # 数据预处理和加载 import torch from torch import nn, optim from torch.utils.data import DataLoader from torchvision import datasets, transforms, …

5.C语言基础入门:数据类型、变量声明与创建详解

C语言基础入门&#xff1a;数据类型、变量声明与创建详解 C语言往期系列文章目录 往期回顾&#xff1a; C语言是什么&#xff1f;编程界的‘常青树’&#xff0c;它的辉煌你不可不知VS 2022 社区版C语言的安装教程&#xff0c;不要再卡在下载0B/s啦C语言入门&#xff1a;解锁…

Github优质项目推荐 - 第六期

文章目录 Github优质项目推荐 - 第六期一、【WiFiAnalyzer】&#xff0c;3.4k stars - WiFi 网络分析工具二、【penpot】&#xff0c;33k stars - UI 设计与原型制作平台三、【Inpaint-Anything】&#xff0c;6.4k stars - 修复图像、视频和3D 场景中的任何内容四、【Malware-P…

小程序项目实践(一)--项目的初始化以及前期的准备工作

目录 1.起步 1.1 uni-app 简介 1.2 开发工具 1.2.1 下载 HBuilderX 1.2.2 安装 HBuilderX 1.2.3 安装 scss/sass 编译 1.2.4 快捷键方案切换 1.2.5 修改编辑器的基本设置 1.3 新建 uni-app 项目 1.4 目录结构 1.5 把项目运行到微信开发者工具 1.6 使用 Git 管理项目 …

leetcode hot100_part3_滑动窗口

滑动窗口是有一个基本的模版的&#xff0c;不要自己想当然哦~ 滑动窗口算法思想&#xff08;附经典例题&#xff09;_滑动窗口的思想-CSDN博客 滑动窗口也叫同向双指针&#xff1b;可以先看一下灵山视频&#xff1a;滑动窗口【基础算法精讲 03】_哔哩哔哩_bilibili 3.无重复字…

7.C++面向对象3(拷贝构造函数,赋值运算符重载)

⭐本篇为C学习第7章&#xff0c;主要了解 拷贝构造函数&#xff0c;赋值运算符重载 ⭐本人Gitee C代码仓库&#xff1a;yzc的c学习: 小川c的学习记录 - Gitee.com 上篇讲了6个默认成员函数的构造函数和析构函数。 重要代码如下&#xff1a; #define _CRT_SECURE_NO_WARNINGS…

Mysql(五) --- 数据库设计

文章目录 前言1.范式1.1.第一范式1.1.1 定义1.1.2.例子 1.2.第二范式1.2.1 定义1.2.2 例子1.2.3.不满足第二范式可能会出现的问题 1.3.第三范式1.3.1 定义2.3.2 示例 2. 设计过程3. 实体-关系图3.1 E-R图的基本组成3.2 关系的类型3.2.1 一对一关系(1:1)3.2.2 ⼀对多关系(1:N)3.…

Pr:视频效果快速参考(合集 · 2024版)

Premiere Pro 自带十七组约一百多个视频效果&#xff0c;涵盖了从变换、颜色控制到风格化等多种用途&#xff0c;帮助用户在视频编辑中实现多样化的视觉表现、进行后期处理以及修正各种画质问题。 提示&#xff1a; 点击下面的效果组名称或截图&#xff0c;即可访问该组里面的效…