NIO(New IO)和BIO(Blocking IO)的区别

Java中的NIO(New IO)和BIO(Blocking IO)的区别及NIO的核心组件

Java中的NIO(New IO)和BIO(Blocking IO)是两种不同的网络通信模型,各自具有独特的特性和适用场景。下面将详细探讨它们之间的区别以及NIO的核心组件。

BIO(Blocking IO)

BIO是Java最早的I/O模型,也是最简单的一种。在BIO模型中,每个I/O操作都会阻塞当前线程,直到数据准备就绪或者超时,才会继续执行下一步操作。这意味着如果有大量的并发连接,就需要创建大量的线程来处理这些连接,会造成资源浪费和性能下降。

BIO通常采用的是一对一的客户端-服务器模型,即每个客户端连接都需要对应一个服务器端的线程来处理。这样的模型适用于连接数较少且连接持续时间较长的场景,但不适合高并发、短连接的场景。例如,传统的Web服务器在处理HTTP请求时,如果采用BIO模型,那么每个客户端连接都需要一个独立的线程来处理,当并发连接数增加时,服务器的线程资源会迅速耗尽,性能会急剧下降。

BIO的优点是简单易懂,编程复杂度较低,适用于连接数较少且连接持续时间较长的场景。然而,在高并发情况下,BIO的性能较差,资源消耗大,因此在实际应用中逐渐被NIO等更高效的模型所取代。

NIO(New IO)

NIO是Java在JDK 1.4引入的新的I/O模型,相比于BIO,它提供了更为灵活和高效的网络编程方式。NIO的核心组件包括通道(Channel)、缓冲区(Buffer)和选择器(Selector)。

  1. 通道(Channel)

通道是Java NIO中用于数据读写的对象,类似于传统I/O中的流。但与传统I/O的流不同,通道支持非阻塞I/O操作,并且可以同时进行读写操作。这意味着线程在等待数据完全传输过来后才能处理数据,从而提高了系统的并发性。

通道是全双工的,即它可以同时用于读和写操作。常见的通道类型包括FileChannel(用于文件读写)、DatagramChannel(用于UDP网络读写)、SocketChannel(用于TCP网络读写)和ServerSocketChannel(用于监听TCP连接)。

  1. 缓冲区(Buffer)

缓冲区是NIO中用于在通道和应用程序之间传输数据的中介。它是一个对象,包含一些要写入或者读出的数据。在面向流的I/O中,可以将数据直接写入或读到Stream对象中,而在NIO中,所有的数据都是用缓冲区处理的。

缓冲区实质是一个数组,通常是一个字节数组(ByteBuffer),也可以使用其他类型的数组。除了ByteBuffer,还有其他类型的缓冲区,如CharBuffer(字符缓冲区)、ShortBuffer(短整型缓冲区)、IntBuffer(整型缓冲区)、LongBuffer(长整型缓冲区)、FloatBuffer(浮点型缓冲区)和DoubleBuffer(双精度浮点型缓冲区)。

缓冲区提供了对数据的结构化访问以及维护读写位置(limit)等信息。在数据读写过程中,需要不断切换缓冲区的读写模式,如flip()方法用于将缓冲区从写模式切换到读模式,clear()方法用于清空缓冲区以便下次使用。

  1. 选择器(Selector)

选择器是NIO中用于监听多个通道的事件的机制。它可以同时监听多个通道(Channel)的I/O事件,如读事件、写事件、连接事件等,使得一个单独的线程可以管理多个通道,进一步提高了系统的并发性。

选择器只能管理非阻塞的通道。当通道发生感兴趣的事件时,选择器会通知对应的线程进行处理。这样,一个线程就可以同时处理多个连接,避免了BIO模型中为每个连接创建一个线程的资源浪费。

NIO模型中的关键是非阻塞通道和选择器。通过使用单线程或少量线程配合选择器,可以实现同时处理多个连接,从而提高了系统的并发处理能力。NIO模型适用于高并发、短连接的场景,如Web服务器、游戏服务器等。它的设计理念是通过少量线程处理大量并发连接,避免了线程资源的浪费和上下文切换的开销,从而提高了系统的性能和吞吐量。

NIO的线程模型

NIO主要包含三种线程模型:Reactor单线程模型、Reactor多线程模型和主从Reactor多线程模型。

  1. Reactor单线程模型

在单线程模型中,单个线程完成所有事情,包括接收客户端的TCP连接请求、读取和写入套接字数据等。这种模型适用于一些小容量应用场景,但对于高负载、大并发的应用却不合适。因为单个NIO线程同时处理成百上千的链路,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送。

  1. Reactor多线程模型

Reactor多线程模型与单线程模型最大的区别就是有一组NIO线程处理真实的I/O操作。该模型的特点是:

  • 有一个专门的NIO线程(Acceptor线程)用于监听服务端,接收客户端的TCP连接请求。
  • 网络I/O操作(读、写等)由一个NIO线程池负责。线程池可以采用标准的JDK线程池实现,它包含一个任务队列和N个可用的线程。由这些NIO线程负责消息的读取、解码、编码和发送。
  • 一个NIO线程可以同时处理N条链路,但是一个链路只对应一个NIO线程,防止发生并发操作问题。

在绝大多数场景下,Reactor多线程模型都可以满足性能需求。但是,在极特殊应用场景中,一个NIO线程负责监听和处理所有的客户端连接可能会存在性能问题。例如,百万客户端并发连接,或者服务端需要对客户端的握手消息进行安全认证,认证本身非常损耗性能。在这些场景下,单独一个Acceptor线程可能会存在性能不足问题,为了解决性能问题,产生了第三种Reactor线程模型——主从Reactor多线程模型。

  1. 主从Reactor多线程模型

主从Reactor多线程模型与Reactor多线程模型的最大区别就是有一组NIO线程处理连接、读写事件。该模型的特点是:

  • 服务端用于接收客户端连接的不再是一个单独的NIO线程,而是一个独立的NIO线程池(Acceptor线程池)。
  • Acceptor接收到客户端TCP连接请求处理完成后(可能包含接入认证等),将新创建的SocketChannel注册到I/O线程池(sub reactor线程池)的某个I/O线程上,由它负责SocketChannel的读写和编解码工作。
  • Acceptor线程池仅仅只用于客户端的登陆、握手和安全认证。一旦链路建立成功,就将链路注册到后端subReactor线程池的I/O线程上,由I/O线程负责后续的I/O操作。

即从多线程模型中由一个线程来监听连接事件和数据读写事件,拆分为一个线程监听连接事件,线程池的多个线程监听已经建立连接的套接字的数据读写事件。另外和多线程模型一样,有专门的线程池处理真正的I/O操作。

NIO与BIO的比较

NIO和BIO各有优缺点,适用于不同的应用场景。

  1. 编程复杂度

BIO编程简单易懂,适用于连接数较少且连接持续时间较长的场景。而NIO提供了非阻塞、多路复用的网络编程方式,编程复杂度较高,但适用于高并发、短连接的场景。

  1. 性能

BIO在高并发情况下性能较差,因为每个连接都需要一个独立的线程来处理,线程资源消耗大。而NIO通过非阻塞通道和选择器,可以实现同时处理多个连接,提高了系统的并发处理能力,性能优于BIO。

  1. 资源消耗

BIO在大量并发连接时,会创建大量的线程,造成资源浪费和性能下降。而NIO通过少量线程处理大量并发连接,避免了线程资源的浪费和上下文切换的开销,从而提高了系统的性能和吞吐量。

  1. 适用场景

BIO适用于连接数较少且连接持续时间较长的场景,如传统的Web服务器在处理HTTP请求时。而NIO适用于高并发、短连接的场景,如现代的Web服务器、游戏服务器等。

应用场景示例

在Java生态系统中,许多中间件和框架都涉及到了NIO和BIO的使用,以实现高性能的网络通信。以下是一些常见的中间件和框架的示例:

  1. Netty

Netty是一个高性能的异步事件驱动的网络应用框架,它基于NIO实现了网络通信的高性能和可扩展性。Netty广泛应用于分布式系统、即时通信系统等领域。

  1. Apache MINA

Apache MINA是一个基于Java的网络应用框架,提供了可扩展的高性能的基于NIO的网络通信。它与Netty类似,但有一些不同的设计理念和API。

  1. Tomcat

Tomcat是一个流行的Java Servlet容器,它在处理HTTP请求时可以选择使用NIO或BIO。通过配置Connector的协议,可以选择不同的I/O模型来处理请求,以满足应用程序的性能和需求。

  1. Jetty

Jetty是另一个流行的Java Servlet容器和Web服务器,它也支持使用NIO或BIO来处理网络连接。

  1. Apache HTTP Server

Apache HTTP Server是世界上最流行的Web服务器之一,它在处理HTTP请求时可以使用NIO或者传统的多线程模型。

  1. Redis

Redis是一个内存数据库,它的网络通信层使用了NIO来实现高性能的异步I/O。

  1. MySQL Connector/J

MySQL的Java连接器,它可以使用NIO来实现异步的数据库访问。

  1. Spring Framework

Spring Framework是一个全面的Java开发框架,其中的Spring Web模块在处理HTTP请求时可以选择使用NIO或者传统的阻塞I/O。

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

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

相关文章

RabbitMQ延迟消息的实现

RabbitMQ延迟队列的实现 延迟消息是什么延迟消息的实现死信交换机代码实现 延迟消息插件 延迟消息是什么 延迟消息是将消息发送到MQ中,消费者不会立即收到消息,而是过一段时间之后才会收到消息,进行处理。在一些业务中,可以用到延…

HTML5 拖拽 API 深度解析

一、HTML5 拖拽 API 深度解析 1.1 背景与发展 HTML5 的拖拽 API 是为了解决传统拖拽操作复杂而设计的。传统方法依赖鼠标事件和复杂的逻辑计算,而 HTML5 提供了标准化的拖拽事件和数据传递机制,使得开发者能够快速实现从一个元素拖拽到另一个元素的交互…

3D 生成重建017-StyleGaussian用文本或图像对你的3DGS内容进行风格迁移

3D 生成重建017-StyleGaussian用文本或图像对你的3DGS内容进行风格迁移 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 论文 “StyleGaussian: Instant 3D Style Transfer with Gaussian Splatting” 介绍了一种新颖的3D风格迁移方法 StyleGaussian,该方法通…

如何查看电脑的屏幕刷新率?

1、按一下键盘的 win i 键,打开如下界面,选择【系统】: 2、选择【屏幕】-【高级显示设置】 如下位置,显示屏幕的刷新率:60Hz 如果可以更改,则选择更高的刷新率,有助于电脑使用起来界面更加流…

【JVM】JVM基础教程(一)

目录 初识JVM JVM是什么? JVM的功能 解释、即时编译和运行 内存管理 常见的JVM JVM虚拟机规范 HotSpot的发展历程 JVM的组成 字节码文件详解 应用场景 以正确姿势打开字节码文件 ​编辑字节码文件的组成 基本信息 Magic魔数 主副版本号 常量池 接口…

Linux内核查询CONFIG_xxx配置项的方法

前言: 嵌入式开发中经常会查看运行的内核都打开了哪些编译选项,这里提供2种方法: 查看编译环境的.config文件查看正在运行的Linux文件系统中的 /proc/config.gz 文件 编译环境的.config不赘述,下面主要介绍如何简单使用 /proc/c…

Neo4j (desktop) 使用记录

1. neo4j community 使用 第一次使用Neo4j,根据网上的教程安装并配置了community版本, 在终端使用 neo4j.bat console 可以正常打开网页端 但是, 使用 neo4j start , neo4j stop 时会提示 ‘neo4j’ 时非法指令,无法识别 查明原…

【JAVA】Java高级:数据库监控与调优:SQL调优与执行计划的分析

作为Java开发工程师,理解SQL调优和执行计划的分析是至关重要的。这不仅可以帮助我们提高数据库查询的效率,还能减少系统资源的消耗,提升整体应用的性能。 1. SQL调优的重要性 随着数据量的增加和用户请求的增多,数据库的性能问题…

Web3.0:连接分布式未来的纽带

随着技术的不断进步,Web3.0正逐渐成为人们关注的焦点。作为Web的下一代,Web3.0将引领我们进入一个全新的数字时代,重新定义了我们与互联网的关系 Web3.0,也称为“分布式Web”,是互联网的下一代演进。它不仅是信息的传…

2024年认证杯SPSSPRO杯数学建模C题(第一阶段)云中的海盐解题全过程文档及程序

2024年认证杯SPSSPRO杯数学建模 C题 云中的海盐 原题再现: 巴黎气候协定提出的目标是:在2100年前,把全球平均气温相对于工业革命以前的气温升幅控制在不超过2摄氏度的水平,并为1.5摄氏度而努力。但事实上,许多之前的…

throw error; 执行不通过怎么返回解决

子页 async save() { if (this.node.type dataSource) { try { await this.$refs.dataFormDataSource.validate(); // 验证通过,执行后续操作 } catch (error) { this.$message.error(数据源参数验证不通过) throw error; return; } } } 调用页面: a…

【Mac】安装Gradle

1、说明 Gradle 运行依赖 JVM,需要先安装JDK,Gradle 与 JDK的版本对应参见:Java Compatibility IDEA的版本也是有要求Gradle版本的,二者版本对应关系参见:Third-Party Software and Licenses 本次 Gradle 安装版本为…

项目代码第2讲:从0实现LoginController.cs,UsersController.cs、User相关的后端接口对应的前端界面

一、User 1、使用数据注解设置主键和外键 设置主键:在User类的U_uid属性上使用[Key]注解。 设置外键:在Order类中,创建一个表示外键的属性(例如UserU_uid),并使用[ForeignKey]注解指定它引用User类的哪个…

使用mtools搭建MongoDB复制集和分片集群

mtools介绍 mtools是一套基于Python实现的MongoDB工具集,其包括MongoDB日志分析、报表生成及简易的数据库安装等功能。它由MongoDB原生的工程师单独发起并做开源维护,目前已经有大量的使用者。 mtools所包含的一些常用组件如下: mlaunch支…

nginx不允许静态文件被post请求显示405 not allowed

在单独站点的配置文件中 添加error_page 405 200 $request_uri; 即可!

golang 汉字转拼音

导入包 # 支持多音字,音调标识等 go get github.com/mozillazg/go-pinyin简单示例 func Test() {// 配置选项opts : pinyin.NewArgs()opts.Style pinyin.Normal // 设置拼音的样式(普通拼音)var test_text "你好世界"test_piny…

MFC扩展库BCGControlBar Pro v36.0新版亮点:黑色主题中的自动反转图标

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中,并为您节省数百个开发和调试时间。 BCGControlBar专业版 v36.0已全新发布了,这个版本在黑暗主题中添加自动图标反转、新增一个全新的S…

MFC工控项目实例三十五读取数据库数据

点击按钮打开文件夹中的数据文件生成曲线 相关代码 void CSEAL_PRESSUREDlg::OnTesReport() {CFileDialog dlgOpen(TRUE/*TRUE打开,FALSE保存*/,0,0,OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST,"All Files(mdb.*)|*.*||",//文件过滤器NULL);CString mdb_1, m…

jwt 与 sessionid 的区别及应用场景

在现代 Web 应用中,JWT(JSON Web Token)和SessionID是两种常用的用户认证和状态管理机制。本文从两者的原理、区别、优缺点以及适用场景展开分析,结合常见问题提出了最佳实践建议,帮助开发者更好地选择和使用。 JWT与S…

反向传播算法中的误差项

背景 在反向传播算法中,我们需要计算每个神经元的误差项,以便更新网络中的权重。对于输出层的神经元,误差项的计算公式如下: 其中: E是损失函数(例如均方误差)。 zk 是输出层神经元的加权输入&a…