在 Java 的 I/O 模型中,NIO(Non - Blocking I/O,非阻塞 I/O)是对 BIO 的重要改进。它为高并发场景提供了更高效的处理方式,在众多 Java 应用中发挥着关键作用。

        NIO模型的核心在于非阻塞和多路复用,其采用 “一个线程处理多个连接” 的模式,主要依靠通道(Channel)、缓冲区(Buffer)和选择器(Selector)这三个核心组件协同工作,每个核心组件的功能原理和功能如下:

(1)通道:通道是数据传输的通道,类似于 BIO 中的流,但它是双向的,既可以从通道读取数据,也可以向通道写入数据。常见的通道有ServerSocketChannel(用于服务器端监听连接)、SocketChannel(用于客户端与服务器端的通信)等。​

(2)缓冲区:缓冲区是存储数据的容器,所有数据的读写都必须通过缓冲区进行。它本质上是一个数组,提供了对数据的结构化访问以及维护读写位置等信息。在 NIO 中,数据从通道读取到缓冲区,或从缓冲区写入到通道。​

(3)选择器:选择器是 NIO 实现多路复用的关键。它可以同时监控多个通道的事件(如连接请求、数据可读、数据可写等)。一个线程通过选择器注册多个通道,然后阻塞在选择器上,等待通道事件的发生。当有事件发生时,线程会处理这些事件,从而实现一个线程高效处理多个连接。​

        其工作流程大致为:服务器端通过ServerSocketChannel监听端口,将其注册到选择器上,并设置关注的事件(如接受连接事件)。客户端通过SocketChannel发起连接。选择器不断轮询注册的通道,当某个通道有事件发生时,就会被选中。线程从选择器中获取这些就绪的通道,进行相应的处理,如接受连接、读取数据、写入数据等,且这些操作大多是非阻塞的。​

        作为BIO的改进型,NIO也是有着许多优点,例如:​

(1)高并发处理能力强:借助多路复用机制,一个线程可以处理多个连接,大大减少了线程的创建和销毁带来的开销,以及线程上下文切换的成本,能在高并发场景下保持较好的性能。​

(2)非阻塞提升效率:在数据读写过程中,线程不会一直阻塞等待,当没有数据可读或可写时,线程可以去处理其他通道的事件,提高了线程的利用率。​

(3)双向传输更灵活:通道是双向的,相比 BIO 中流的单向传输,在一些需要双向数据交互的场景中,使用更方便灵活。​

        但是同样的,其缺点也不少,如:​

(1)编程复杂度高:NIO 的编程模型相对 BIO 更为复杂,需要理解通道、缓冲区、选择器等多个组件的协同工作机制,对开发者的技术要求较高。​

(2)学习门槛较高:其涉及的多路复用、非阻塞等概念较难理解,新手需要花费更多的时间和精力去掌握。​

(3)在低并发场景下优势不明显:在并发量较小的情况下,NIO 的优势难以体现,其复杂的机制可能还会带来一些额外的开销。​

        下面通过一个简单的客户端 - 服务器通信示例来展示 Java NIO 的使用。​

服务器端代码​

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;public class NioServer {public static void main(String[] args) throws IOException {// 创建ServerSocketChannel并绑定端口ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8888));// 设置为非阻塞模式serverSocketChannel.configureBlocking(false);// 创建选择器Selector selector = Selector.open();// 将ServerSocketChannel注册到选择器,关注接受连接事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("服务器启动,监听端口8888...");while (true) {// 阻塞等待通道事件,返回就绪的通道数量int readyChannels = selector.select();if (readyChannels == 0) {continue;}// 获取就绪的事件Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();// 移除处理过的事件,避免重复处理iterator.remove();if (key.isAcceptable()) {// 处理接受连接事件ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel socketChannel = serverChannel.accept();socketChannel.configureBlocking(false);// 将客户端通道注册到选择器,关注数据可读事件socketChannel.register(selector, SelectionKey.OP_READ);System.out.println("收到新的客户端连接:" + socketChannel.getRemoteAddress());} else if (key.isReadable()) {// 处理数据可读事件SocketChannel socketChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = socketChannel.read(buffer);if (bytesRead > 0) {buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);String message = new String(data);System.out.println("收到客户端消息:" + message);// 向客户端发送响应buffer.clear();String response = "服务器已收到消息:" + message;buffer.put(response.getBytes());buffer.flip();socketChannel.write(buffer);} else if (bytesRead == -1) {// 客户端关闭连接socketChannel.close();System.out.println("客户端连接关闭");}}}}}
}
/*
创建ServerSocketChannel并绑定端口,设置为非阻塞模式,然后注册到选择器上并关注接受连接事件。进入循环后,线程阻塞在选择器的select()方法上,等待通道事件。当有接受连接事件时,接受客户端连接,将客户端的SocketChannel注册到选择器并关注数据可读事件。当有数据可读事件时,从通道中读取数据,处理后向客户端发送响应。
*/

客户端代码​

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;public class NioClient {public static void main(String[] args) throws IOException {// 打开SocketChannel并连接服务器SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 8888));// 设置为非阻塞模式socketChannel.configureBlocking(false);System.out.println("已连接到服务器");// 向服务器发送数据Scanner scanner = new Scanner(System.in);System.out.println("请输入要发送的消息:");String message = scanner.nextLine();ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.put(message.getBytes());buffer.flip();socketChannel.write(buffer);// 读取服务器的响应buffer.clear();int bytesRead = socketChannel.read(buffer);if (bytesRead > 0) {buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);String response = new String(data);System.out.println("收到服务器响应:" + response);}scanner.close();socketChannel.close();System.out.println("客户端连接关闭");}
}
/*
创建SocketChannel连接服务器,设置为非阻塞模式,向服务器发送数据,然后读取服务器的响应,最后关闭连接。
*/

        从代码中能清楚看到 NIO 的非阻塞和多路复用特性,一个线程通过选择器处理多个通道的事件,极大地提高了并发处理能力。​

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

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

相关文章

MySQL计数函数count原理分析

前言 统计表中数据的条数是非常常用的操作,但是咱们常用的InnoDB存储引擎计数函数是现时统计的,所以会出现性能的问题,这次我准备分享计数函数count的原理,保证之后遇到计数方面的问题都可以轻易灵活的解决 与MyISAM存储引擎相比,MyISAM存储引擎是自己记录了表中数据的条数,但…

Day07_网络编程20250721_大项目

基本代码&#xff1a;搭建服务器客户端&#xff0c;要求服务器使用 epoll 模型客户端使用多线程服务器打开数据库&#xff0c;表单格式如下name text primary key pswd text not null客户端做一个简单的界面&#xff1a;1&#xff1a;注册2&#xff1a;登录无论注册还是登录&am…

20250721

P5357 【模板】AC 自动机 - 洛谷 主要是构建fail树 /* 我们可以知道的是&#xff0c;当访问一个点x时&#xff0c;接下来需要跳转其fail[x]&#xff0c;以此类推&#xff0c;如果在某个fail[x]上出现了一个字符串&#xff0c;那么相应的统计次数应该加1&#xff0c;然后当访…

【INT四则优先算式】2022-9-22

缘由ccf201903-2二十四点我用暴力破解做的&#xff0c;但是两个程序一个拿到了满分&#xff0c;一个拿到了50分&#xff0c;看了很长时间也没看出问题在哪里&#xff0c;希望有英雄慧眼帮我看一下-编程语言-CSDN问答 void INT四则优先算式() {//缘由https://ask.csdn.net/ques…

本地k8s集群的搭建

windows机器&#xff0c;考虑如果使用云服务器&#xff0c;每年的开销还是太大&#xff0c;不值得&#xff0c;自己只是做demo&#xff0c;了解各种配置和使用即可&#xff0c;使用VMware的虚拟机来搭建k8s集群 使用docker安装rancher和k8s yum -y install chronycat > /et…

B树、B+树的区别及MySQL为何选择B+树

B树与B树 B树和B树都是自平衡的多路搜索树&#xff0c;广泛应用于数据库和文件系统中&#xff0c;用于高效管理大量数据。它们的设计目标是在磁盘存储环境下减少I/O操作次数&#xff0c;提高数据访问效率。下面我将逐步解释两者的定义、特性、比较以及应用场景&#xff0c;确保…

Unity之可视化编程VisualScripting快速入门

文章目录 前言 脚本机和状态机 脚本图ScriptGraph 脚本图 子图 自定义事件 状态图StateGraph 状态图 Start状态 创建新状态 过渡连接 常用功能 射线检测 补间动画 按钮点击 前言 可视化脚本使您无需编写代码即可为游戏或应用程序创建逻辑。可视化脚本使用基于节点的可视化图形…

2025三掌柜赠书活动第二十五期 网络安全应急响应实战

目录 前言 网络安全的重要性 关于《网络安全应急响应实战》 编辑推荐 内容简介 作者简介 图书目录 《网络安全应急响应实战》全书速览 结束语 前言 在当今数字化时代&#xff0c;网络安全已经成为企业和个人都无法忽视的重要问题。随着网络技术的飞速发展&#xff0c;…

车载软件架构 --- 软件开发面临的问题

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…

MySQL 8.0 OCP 1Z0-908 题目解析(31)

题目121 Choose two. Examine this command, which executes successfully on InnoDB Cluster: dba.dropMetadataSchema() Which two statements are true? □ A) The mysql_innodb_cluster_metadata schema is dropped from the instance where the connection was establish…

本地生活服务 app 同城信息发布系统搭建

一、逻辑分析用户需求层面&#xff1a;对于发布者来说&#xff0c;需要一个便捷的界面来输入同城信息&#xff0c;包括但不限于房屋租售、招聘求职、二手交易、活动推广等各类信息。发布者要能够上传相关图片、详细描述信息内容、设置价格&#xff08;如果有需要&#xff09;、…

[Python] -项目实战4- 利用Python进行Excel批量处理

一、为什么要批量处理Excel文件? 节省时间:人工对数十、数百个 Excel 文件重复操作不现实,Python 批量处理一次搞定。 保证一致性:统一格式、统一操作,避免手动误差。 易于集成:可嵌入日常自动化流程,支持定时和触发执行。 二、常用库及选型建议 库 作用 优势 局限 p…

社区搜索离线回溯系统设计:架构、挑战与性能优化|得物技术

一、项目背景在社区场景中&#xff0c;我们积累了丰富的用户互动数据。这些历史互动信息对CTR/CVR预估建模具有重要参考价值&#xff0c;用户的每次互动都反映了其特定维度的偏好特征。当前&#xff0c;已在多个业务实践中验证&#xff0c;基于用户历史互动特征进行未来行为预测…

WPF——自定义ListBox

在阅读本文前&#xff0c;最好先看看WPF——自定义RadioButton 背景 WPF中实现单选功能通常有两种方案&#xff1a; - RadioButton组&#xff1a;传统方案&#xff0c;但代码冗余 - ListBox定制&#xff1a;通过样式改造&#xff0c;兼顾数据绑定和UI灵活性 需求 一组选项中…

rancher上使用rke在华为云多网卡的服务器上安装k8s集群问题处理了

报错:问题&#xff1a;[[network] Host [192.168.0.213] is not able to connect to the following ports: [192.168.0.213:2379]. Please check network policies and firewall rules]问题&#xff1a; roothwy-isms-210-66:~# gotelnet 172.17.210.66 2379 map[2379:failed] …

xformers包介绍及代码示例

文章目录主要特性安装方式主要优势使用场景注意事项代码示例xFormers是由Meta开发的一个高性能深度学习库&#xff0c;专门用于优化Transformer架构中的注意力机制和其他组件。它提供了内存高效和计算高效的实现&#xff0c;特别适用于处理长序列和大规模模型。github地址&…

CityEngine自动化建模

CityEngine学习记录 学习网址&#xff1a; 百度安全验证 CityEngine-CityEngine_Rule-based_Modeling-基于规则建模和输出模型 - 豆丁网 CityEngine 初探-CSDN博客 City Engine CGA 规则包_cga规则-CSDN博客 CityEngine学习记录 学习网址&#xff1a;百度安全验证 CityE…

Nacos+LoadBalancer实现服务注册与发现

目录 一、相关文章 二、兼容说明 三、服务注册到Nacos 四、服务发现 五、服务分级存储模型 六、查看集群服务 七、LoadBalancer负载均衡 一、相关文章 基础工程&#xff1a;gradle7.6.1springboot3.2.4创建微服务工程-CSDN博客 Nacos服务端安装&#xff1a;Nacos服务端…

事务并发-封锁协议

事务并发数据库里面操作的是事务。事务特性&#xff1a;原子性&#xff1a;要么全做&#xff0c;要么不做。一致性&#xff1a;事务发生后数据是一致的。隔离性&#xff1a;任一事务的更新操作直到其成功提交的整个过程对其他事务都是不可见的&#xff0c;不同事务之间是隔离的…

大气波导数值预报方法全解析:理论基础、预报模型与误差来源

我们希望能够像天气预报一样&#xff0c;准确预测何时、何地会出现大气波导&#xff0c;其覆盖范围有多大、持续时间有多长&#xff0c;以便为通信、雷达等应用提供可靠的环境保障。 目录 &#xff08;一&#xff09;气象预报 1.1 气象预报的分类 1.2 大气数值预报基础 1.2…