详解Java中的BIO、NIO、AIO
1、 详解Java中的BIO、AIO、NIO
1.1、引言
IO流是Java中比较难理解的一个知识点,但是IO流在实际的开发场景中经常会使用到,比如Dubbo底层就是NIO进行通讯。本文将介绍Java发展过程中出现的三种IO:BIO、NIO以及AIO,重点介绍NIO。
1.2、什么是BIO
BIO即同步阻塞IO,实现模型为一个连接就需要一个线程去处理。这种方式简单来说就是当有客户端来请求服务器时,服务器就会开启一个线程去处理这个请求,即使这个请求不干任何事情,这个线程都一直处于阻塞状态。
BIO模型有很多缺点,最大的缺点就是资源的浪费。想象一下如果QQ使用BIO模型,当有一个人上线时就需要一个线程,即使这个人不聊天,这个线程也一直被占用,那再多的服务器资源都不管用。
代码演示:package com.atguigu.bio;import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class BIOServer {public static void main(String[] args) throws Exception {//线程池机制//思路//1. 创建一个线程池//2. 如果有客户端连接,就创建一个线程,与之通讯(单独写一个方法)ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();//创建ServerSocketServerSocket serverSocket = new ServerSocket(6666);System.out.println("服务器启动了");while (true) {System.out.println("线程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());//监听,等待客户端连接System.out.println("等待连接....");final Socket socket = serverSocket.accept();System.out.println("连接到一个客户端");//就创建一个线程,与之通讯(单独写一个方法)newCachedThreadPool.execute(new Runnable() {public void run() { //我们重写//可以和客户端通讯handler(socket);}});}}//编写一个handler方法,和客户端通讯public static void handler(Socket socket) {try {System.out.println("线程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());byte[] bytes = new byte[1024];//通过socket 获取输入流InputStream inputStream = socket.getInputStream();//循环的读取客户端发送的数据while (true) {System.out.println("线程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());System.out.println("read....");int read = inputStream.read(bytes);if(read != -1) {System.out.println(new String(bytes, 0, read)); //输出客户端发送的数据} else {break;}}}catch (Exception e) {e.printStackTrace();}finally {System.out.println("关闭和client的连接");try {socket.close();}catch (Exception e) {e.printStackTrace();}}}
}
演示
快捷键win+R打开cmd窗口,根据上面代码拼写6666端口
输入 telnet 127.0.0.1 6666
进入黑窗口
输入ctrl+]
向服务端发送文本
send hello world
服务端接收的
当有
多个cmd窗口时,则创建多一个线程与之对应
退出时,cmd输入
quit
服务端显示
2、什么是NIO
BIO是阻塞的,如果没有多线程,BIO就需要一直占用CPU,而NIO则是非阻塞IO,NIO在获取连接或者请求时,即使没有取得连接和数据,也不会阻塞程序。NIO的服务器实现模式为一个线程可以处理多个请求(连接)。
NIO有几个知识点需要掌握,Channel(通道),Buffer(缓冲区), Selector(多路复用选择器)。
Channel既可以用来进行读操作,又可以用来进行写操作。NIO中常用的Channel有FileChannel
、SocketChannel、ServerSocketChannel、DatagramChannel。
Buffer缓冲区用来发送和接受数据。
Selector 一般称为选择器或者多路复用器 。它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。在javaNIO中使用Selector往往是将Channel注册到Selector中。
下面我通过代码的方式模拟javaNIO的运行流程。
2.1、NIO代码实践
首先贴上NIO的实践代码:NIO服务端详细的执行过程是这样的:创建一个ServerSocketChannel和Selector,然后将ServerSocketChannel注册到Selector上
Selector通过select方法去轮询监听channel事件,如果有客户端要连接时,监听到连接事件。
通过channel方法将socketchannel绑定到ServerSocketChannel上,绑定通过SelectorKey实现。
socketchannel注册到Selector上,关心读事件。
Selector通过select方法去轮询监听channel事件,当监听到有读事件时,ServerSocketChannel通过绑定的SelectorKey定位到具体的channel,读取里面的数据。
public class NioServer {public static void main(String[] args) throws IOException {//创建一个socket通道,并且设置为非阻塞的方式ServerSocketChannel serverSocketChannel=ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.socket().bind(new InetSocketAddress(9000));//创建一个selector选择器,把channel注册到selector选择器上Selector selector=Selector.open();serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true){System.out.println("等待事件发生");selector.select();System.out.println("有事件发生了");Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()){SelectionKey key = iterator.next();iterator.remove();handle(key);}}}private static void handle(SelectionKey key) throws IOException {if (key.isAcceptable()){System.out.println("连接事件发生");ServerSocketChannel serverSocketChannel= (ServerSocketChannel) key.channel();//创建客户端一侧的channel,并注册到selector上SocketChannel socketChannel = serverSocketChannel.accept();socketChannel.configureBlocking(false);socketChannel.register(key.selector(),SelectionKey.OP_READ);}else if (key.isReadable()){System.out.println("数据可读事件发生");SocketChannel socketChannel= (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int len = socketChannel.read(buffer);if (len!=-1){System.out.println("读取到客户端发送的数据:"+new String(buffer.array(),0,len));}//给客户端发送信息ByteBuffer wrap = ByteBuffer.wrap("hello world".getBytes());socketChannel.write(wrap);key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);socketChannel.close();}}
}
客户端代码:NIO客户端代码的实现比BIO复杂很多,主要的区别在于,NIO的客户端也需要去轮询自己和服务端的连接情况。
客户端发送数据后,获取到了来自服务端的回复。
2.2、NIO总结
NIO通过一个Selector,负责监听各种IO事件的发生,然后交给后端的线程去处理。NIO相比与BIO而言,非阻塞体现在轮询处理上。BIO后端线程需要阻塞等待客户端写数据,如果客户端不写数据就一直处于阻塞状态。而NIO通过Selector进行轮询已注册的客户端,当有事件发生时才会交给后端去处理,后端线程不需要等待。
3、什么是AIO
AIO是在JDK1.7中推出的新的IO方式–异步非阻塞IO,也被称为NIO2.0,AIO在进行读写操作时,直接调用API的read和write方法即可,这两种均是异步的方法,且完成后会主动调用回调函数。简单来讲,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。
Java提供了四个异步通道:AsynchronousSocketChannel、AsynchronousServerSocketChannel、AsynchronousFileChannel、AsynchronousDatagramChannel。
3.1、AIO代码实践
服务器端代码:AIO的创建方式和NIO类似,先创建通道,再绑定,再监听。只不过AIO中使用了异步的通道。
public class AIOServer {public static void main(String[] args) {try {//创建异步通道AsynchronousServerSocketChannel serverSocketChannel=AsynchronousServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));System.out.println("等待连接中");//在AIO中,accept有两个参数,// 第一个参数是一个泛型,可以用来控制想传递的对象// 第二个参数CompletionHandler,用来处理监听成功和失败的逻辑// 如此设置监听的原因是因为这里的监听是一个类似于递归的操作,每次监听成功后要开启下一个监听serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {//请求成功处理逻辑@Overridepublic void completed(AsynchronousSocketChannel result, Object attachment) {System.out.println("连接成功,处理数据中");//开启新的监听serverSocketChannel.accept(null,this);handledata(result);}@Overridepublic void failed(Throwable exc, Object attachment) {System.out.println("失败");}});try {TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}} catch (IOException e) {e.printStackTrace();}}private static void handledata(AsynchronousSocketChannel result) {ByteBuffer byteBuffer=ByteBuffer.allocate(1024);//通道的read方法也带有三个参数//1.目的地:处理客户端传递数据的中转缓存,可以不使用//2.处理客户端传递数据的对象//3.处理逻辑,也有成功和不成功的两个写法result.read(byteBuffer, byteBuffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer attachment) {if (result>0){attachment.flip();byte[] array = attachment.array();System.out.println(new String(array));}}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {System.out.println("失败");}});}
}
客户端代码基本上没有太多差别,主要还是实现数据的发送功能
public class AIOClient {public static void main(String[] args) {try {AsynchronousSocketChannel socketChannel=AsynchronousSocketChannel.open();socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));Scanner scanner=new Scanner(System.in);String next = scanner.next();ByteBuffer byteBuffer=ByteBuffer.allocate(1024);byteBuffer.put(next.getBytes());byteBuffer.flip();socketChannel.write(byteBuffer);} catch (IOException e) {e.printStackTrace();}}
}
观察结果:
相关文章:

详解Java中的BIO、NIO、AIO
1、 详解Java中的BIO、AIO、NIO 1.1、引言 IO流是Java中比较难理解的一个知识点,但是IO流在实际的开发场景中经常会使用到,比如Dubbo底层就是NIO进行通讯。本文将介绍Java发展过程中出现的三种IO:BIO、NIO以及AIO,重点介绍NIO。…...

CAN和CANFD如何转换和通信
随着科技的发展,汽车电子和工业领域中CAN通信需要承载数据量也越来越大,传统CAN通信有了向CANFD通信过渡的倾向。在实现过渡的过程中可能会出现自己设备是CAN通信,客户设备是CANFD通信的情况,或者自己设备是CANFD通信,…...

QDateTimeEdit Class
Header:#include qmake:QT += widgets Inherits:QAbstractSpinBox Inherited By:QDateEdit and QTimeEdit Public Types enum Section {NoSection, AmPmSection, MSecSection, SecondSection, MinuteSection, …, YearSection } flags SectionsProperties calendarPopu…...

Windows环境安装CentOS7
【注意】安装CentOS需要先安装Vmware虚拟机 【下载前准备】 一、下载CentOS 7镜像文件阿里云镜像开源,点击跳转 二、安装VMware(17): a. 官网,点击跳转 b. 许可证:JU090-6039P-08409-8J0QH-2YR7F 安装V…...

用docker启动mysql步骤
以下是在 Docker 中启动 MySQL 的详细步骤: **一、拉取 MySQL 镜像 ** 1. 打开终端,确保 Docker 服务正在运行。可以使用以下命令检查 Docker 服务状态: sudo systemctl status docker 2. 使用以下命令拉取 MySQL 官方镜像: d…...

[Linux] Linux 初识进程地址空间 (进程地址空间第一弹)
标题:[Linux] Linux初识进程地址空间 个人主页水墨不写bug (图片来源于AI) 目录 一、什么是进程地址空间 二、为什么父子进程相同地址的变量的值不同 三、初识虚拟地址、页表 一、什么是进程地址空间 其实,在很久之前…...

力扣21~25题
21题(简单): 分析: 按要求照做就好了,这种链表基本操作适合用c写,python用起来真的很奇怪 python代码: # Definition for singly-linked list. # class ListNode: # def __init__(self, v…...

04. prometheus 监控 Windows 服务器
prometheus 监控 Windows 服务器 1. 下载安装 Windows_exporter 安装包下载:https://github.com/prometheus-community/windows_exporter/releases 下载 msi 版本,上传至要监控的 Windows 服务器,双击安装即可,exporter 会自动…...

【机器学习】——决策树以及随机森林
文章目录 1. 决策树的基本概念与结构1.1 决策树的构建过程 2. 决策树的划分标准2.1 信息增益(Information Gain)2.2 信息增益比(Information Gain Ratio)2.3 基尼指数(Gini Index)2.4 均方误差(…...

怎么选择合适的数据恢复软件?适用于 Windows 的数据恢复软件对比
针对 Windows 的领先数据恢复软件的全面回顾: 丢失重要数据对任何 Windows 用户来说都是一场噩梦。从意外删除到系统崩溃,数据丢失是一个非常普遍的问题。值得庆幸的是,有强大的数据恢复工具可以帮助找回丢失的文件。这篇评论深入探讨了适用于…...

CI/CD 和 DevOps 工具概述:Jenkins 、Docker 的概述、工作流程、对比
随着软件开发的复杂性不断增加,持续集成(CI)、持续交付(CD)和运维(Ops)的概念逐渐成为现代软件开发流程中的核心组成部分。这些概念促进了开发团队与运维团队之间的协作,提升了软件的…...

基于SpringBoot+Vue+uniapp的高校教务管理小程序系统设计和实现
2. 详细视频演示 文章底部名片,联系我获取更详细的演示视频 3. 论文参考 4. 项目运行截图 代码运行,效果展示图 代码运行,效果展示图 代码运行,效果展示图 代码运行,效果展示图 代码运行,效果展示图 5. 技…...

如何在 Ubuntu VPS 上从 Apache Web 服务器迁移到 Nginx
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 简介 在启动网站或应用程序时,您需要做出许多选择。有时,您的需求会发生变化,新技术变得可行&#x…...

pikachu靶场总结(一)
最近看到好多人还在打这个靶机所以把以前写的总结放上来了,主要是皮卡丘靶场漏洞的原理,利用方式,防护方法简略总结,纯手敲记录,总结如果不到位请评论区留言! 一、暴力破解 1.基于表单的暴力破解 原理&a…...

No.2 笔记 | 网络安全攻防:PC、CS工具与移动应用分析
引言 在当今数字化时代,网络安全已成为每个人都应该关注的重要话题。本文将总结一次关于网络安全攻防技术的学习内容,涵盖PC端和移动端的恶意程序利用,以及强大的渗透测试工具Cobalt Strike的使用。通过学习这些内容,我们不仅能够了解攻击者的手法,更能提高自身的安全意识和防…...

QD1-P8 HTML格式化标签
本节学习:HTML 格式化标签。 本节视频 www.bilibili.com/video/BV1n64y1U7oj?p8 一、font 标签 用途:定义文本的字体大小、颜色和 face(字体类型)。 示例 <!DOCTYPE html> <html><head><meta cha…...

WordPress修改固定链接后301的重定向方法
网站改版实际上是很忌讳的,尤其是针对已被搜索引擎收录的网站,新站不用考虑这些问题,而已经收录的网站网页在不遵守搜索引擎规则的前提下,是会被降权,关键词排名下滑、流量IP会被剥夺、收录会减少 、业务成交量会急剧下…...

关于Allegro导出Gerber时的槽孔问题
注意点一: 如果设计的板子中有 槽孔和通孔(俗称圆孔),不仅要NC Drill, 还要 NC Route allegro导出的槽孔文件后缀是 .rou 圆型孔后缀 是 .drl ,出gerber时需要看下是否有该文件。 注意点二: 导出钻孔文件时,设置参…...

平时使用的正则总结
1、将某一个字符串的后缀名后面加上“!400_500” 使用场景是将minio拿过来的图片压缩尺寸从而压缩其大小,加快渲染的速度。需要在图片的后缀名后面加上尺寸如下: const str //storage-test.test.shiqiao.com/gateway/common/isopen/2024/10/09/e708e9…...

[万字解析]从零开始使用transformers微调huggingface格式的中文Bert模型的过程以及可能出现的问题
系列文章目录 使用transformers中的pipeline调用huggingface中模型过程中可能遇到的问题和修改建议 [万字解析]从零开始使用transformers微调huggingface格式的中文Bert模型的过程以及可能出现的问题 文章目录 系列文章目录前言模型与数据集下载模型下载数据集下载 数据加载、…...

K8s简介及环境搭建
一、Kubernetes简介 kubernetes 的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能: 自我修复:一旦某一个容器崩溃&a…...

Python对PDF文件页面的旋转和切割
Python对PDF文件页面的旋转和切割 利用Python的.rotate()方法和.mediabox属性对PDF页面进行旋转和切割,最终生成一个PDF。下面结合案例进行说明,本示例中的名为split_and_rotate.pdf文件在practice_files文件夹中, 示例(1&#…...

Android 10.0 修改Systemui三键导航栏虚拟按键颜色功能实现
1.前言 在10.0的系统ROM定制化开发中,在对systemui的相关定制化开发中,在某些产品中,需要修改相关的 导航栏三键导航的虚拟按键的颜色,修改掉原来默认的虚拟按键的黑白色,接下来就来实现相关的功能 2.修改Systemui三键导航栏虚拟按键颜色功能实现的核心类 frameworks\ba…...

『网络游戏』客户端使用PESorket发送消息到服务器【14】
上一章服务器已经完成使用PESorket 现在我们将其导出在客户端中使用 生成成功后复制 粘贴到Unity项目中 进入Assets文件夹 粘贴两个.dll 创建脚本:ClientSession.cs 编写脚本: ClientSession.cs 编写脚本:GameStart.cs 将GameStart.cs脚本绑定在摄像机上 运行服务器 运行客户端…...

JVM(学习预热 - 走进Java)(持续更新迭代)
目录 一、彻底认识Java虚拟机 开创世纪:Sun Classic 开创世纪:Exact VM 武林霸主:HotSpot VM 移动端虚拟机:Mobile/Embedded VM “三大”其二:BEA JRockit/IBM J9 VM 软硬结合:BEA Liquid VM/Azul VM…...

43 C 程序动态内存分配:内存区域划分、void 指针、内存分配相关函数(malloc、calloc、realloc、_msize、free)、内存泄漏
目录 1 C 程序内存区域划分 1.1 代码区 (Code Section) 1.2 全局/静态区 (Global/Static Section) 1.3 栈区 (Stack Section) 1.4 堆区 (Heap Section) 1.5 动态内存分配 2 void 指针(无类型指针) 2.1 void 指针介绍 2.2 void 指针的作用 2.3 …...

编译链接的过程发生了什么?
一:程序的翻译环境和执行环境 在 ANSI C 的任何一种实现中,存在两个不同的环境。 第 1 种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。 第 2 种是执行环境,它用于实际执行代码 也就是说:↓ 1࿱…...

【D3.js in Action 3 精译_028】3.4 小节 DIY 实战:使用 Observable 在线绘制 D3 条形图
当前内容所在位置(可进入专栏查看其他译好的章节内容) 第一部分 D3.js 基础知识 第一章 D3.js 简介(已完结) 1.1 何为 D3.js?1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践(上)1.3 数据可…...

【Linux】 TCP短服务编写和守护进程
文章目录 TCP 短服务编写流程进程组和会话和守护进程 TCP 短服务编写流程 TCP服务器是面向连接的,客户端在发送数据之前需要先与服务器建立连接。 因此,TCP服务器需要能够监听客户端的连接请求。为了实现这一功能,需要将TCP服务器创建的套接字…...

自学数据库-MYSQL
自学数据库-MYSQL 一.表和视图1.表1.1 表创建1.2 索引1.2.1 这里是废话,不感兴趣的可以直接更具目录的跳过这里的内容1.2.1.1 索引是什么1.2.1.2 相关数据结构:二叉树、红黑树、B-Tree、BTree、Hash…①普通索引②唯一索引③全文索引④组合索引 1.3 表数据操作(更新…...