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

Java-NIO 开篇(1)

NIO简介

高性能的Java通信,离不开Java NIO组件,现在主流的技术框架或中间件服务器,都使用了Java NIO组件,譬如Tomcat、 Jetty、 Netty、Redis、RabbitMQ等的网络通信模块。在1.4版本之前, Java IO类库是阻塞式IO;从1.4版本开始,引进了新的异步IO库,被称为Java New IO类库,简称为Java NIO。 称“老的”阻塞式Java IO为OIO(Old IO)。总体上说, NIO弥补了原来面向流的OIO同步阻塞的不足,它为标准Java代码提供了高速的、面向缓冲区的IO。 学习NIO最主要的要理解Channel(通道)、Selector(选择器)、Buffer(缓冲区)三个核心组件。

在Java中, NIO和OIO的区别,主要体现在三个方面:

  • OIO是面向流(Stream Oriented)的, NIO是面向缓冲区(Buffer Oriented)的。

    如何理解呢?非常简单,假设两个计算机的进程建立了通信,OIO的 read() 操作总是以输入流式的方式顺序地读取读取一个或多个字节,期间要么读要么不读,不能随意乱序读取。而写数据也只能往输出流写入数据。输入流和输出流是单向数据传输的。而NIO引入了Channel(通道)和Buffer(缓冲区)的概念。面向缓冲区的读取和写入,都是与Buffer进行交互。用户程序只需要从通道中读取数据到缓冲区中,或将数据从缓冲区中写入到通道中。 NIO不像OIO那样是顺序操作,可以随意地读取Buffer中任意位置的数据,可以随意修改Buffer中任意位置的数据。如下图所示,通道处于应用层,所有的通信都需要经过Channel通道:

  • OIO的操作是阻塞的,而NIO的操作是非阻塞的。

    OIO阻塞: 当线程执行到read()和write()和连接服务器时的方法期间,如果没有对应的IO事件发生(客户端发送了连接请求、客户端发数据过来了)则一直在这些代码处等待,期间不做任何事情,线程挂起阻塞。直到发生了相应的IO事件才继续往下执行。并且如果还有其他的客户端触发了不是导致阻塞的IO事件也可能被阻塞。假设有两个客户端A和B,服务器伪代码如下所示,当没有客户端建立连接时则下面代码阻塞在第2行,假设此时A请求连接,那么下面代码就执行第2行然后阻塞在第3行。此时B也请求建立连接,这时候B是无法连接的,因为服务器代码阻塞在第3行。如果此时A发送了一个消息,那么下面程序继续执行,获取到A发生过来的消息msg。程序继续执行到第2行,如果因为B还在请求,直到这个时候B才能连接上服务器程序。这个例子就是OIO阻塞。

    // OIO阻塞伪代码,先建立连接在读取客户端发来的数据的代码
    1  while(true){
    2  	 sc = ssc.accept() // 接受客户端连接,阻塞方法
    3    msg = sc.read() // 读取客户端发送过来的数据,阻塞方法
    4  }
    

    NIO非阻塞: NIO的非阻塞实现方法是IO多路复用技术,通过selector来监测事件,如果没有事件发生则进行阻塞,如果有IO事件发生则获取到对应的事件处理对应的事件即可。首先A、B客户端没有连接时,下面程序执行到第2行进行阻塞,因为没有IO事件发生,如果此时A发起了连接则程序执行到第5行代码建立连接,如果此时B突然也请求连接,下面代码因为没有被阻塞经过10纳秒左右就能运行到第2行代码,然后发现B客户的请求连接事件,于是继续往下执行,同样执行到第5行代码。如果B请求连接的同时A突然发生了消息呢?那么没关系,events中有两个事件,通过for循环都能处理,A的消息发生请求会在第7行代码处理掉。下面的代码只是NIO的伪代码,实际上用法有一点点语法上的区别,逻辑是这样的。可以看见NIO是不会阻塞其他客户端的事件的,一般阻塞指的是较长时间的等待,例如1秒或者以上,下面也是单线程的服务器代码。如果你非要说10纳秒也是阻塞,那么下面的代码也确实无法0秒响应,实际上世界上也不存在这样的代码。什么是阻塞,我相信你已经有了自己的认知了!

    // NIO非阻塞伪代码,先建立连接在读取客户端发来的数据的代码
    1 while(true){
    2    events = selector.select() // 没有事件线程阻塞,有事件则接着往下运行
    3    for(E e : event){
    4        if(e是请求事件){
    5            e.connect();
    6        }else if (e是读事件){
    7            msg = e.read();
    8        }....
    9    }
    10 }
    
  • OIO没有选择器( Selector)概念,而NIO有选择器的概念。

    NIO技术的实现, 是基于底层的IO多路复用技术实现的,比如在Windows中需要select多路复用组件的支持,在Linux系统中需要select/poll/epoll多路复用组件的支持。 所以NIO的需要底层操作系统提供支持。而OIO不需要用到选择器selector,相信上面的NIO伪代码让你见识到了selector的威力!

到这里,你已经基本直到了NIO有多么牛了吧,但是还不够,前辈们的核心思想学习还刚刚开始,接下来需要学习非常核心的NIO类库的三大组件:Channel(通道)、Buffer(缓冲区)、Selector(选择器)。

Channel(通道)

Channel的角色和OIO中的Stream(流)是差不多的。 在OIO中,同一个网络连接会关联到两个流:一个输入流( Input Stream),另一个输出流(Output Stream), Java应用程序通过这两个流,不断地进行输入和输出的操作。在NIO中,一个网络连接使用一个Channel( 通道) 表示,所有的NIO的IO操作都是通过连接通道完成的。一个通道类似于OIO中的两个流的结合体,既可以从通道读取数据,也可以向通道写入数据。Channel和Stream的一个显著的不同是: Stream是单向的,譬如InputStream是单向的只读流, OutputStream是单向的只写流; 而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。如下图所示:

在这里插入图片描述

NIO中的Channel的主要实现有:

  1. FileChannel 用于文件IO操作
  2. DatagramChannel 用于UDP的IO操作
  3. SocketChannel 用于TCP的传输操作
  4. ServerSocketChannel 用于TCP连接监听操作

Selector(选择器)

首先回顾一下IO多路复用,指的是一个进程/线程可以同时监视多个socket连接,一旦其中的一个或者多个连接可读或者可写,该监听进程/线程能够进行IO事件的查询。在Java应用层面,Selector 选择器可以理解为一个IO事件的监听与查询器。通过选择器,一个线程可以查询多个通道的IO事件的就绪状态。什么是IO事件呢?表示通道某种IO操作已经就绪、或者说已经做好了准备。例如,如果一个新Channel连接建立成功了,就会在Server Socket Channel上发生一个IO事件,代表一个新连接一个准备好,这个IO事件叫做“接收就绪”事件。 再例如, 一个Channel通道如果有数据可读,就会发生一个IO事件,代表该连接数据已经准备好,这个IO事件叫做 ―“读就绪”事件。Java NIO将NIO事件进行了简化,只定义了四个事件,这四种事件用SelectionKey的四个常量来表示:

  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE

Selector本质就是去查询这些IO就绪事件的,从编程实现维度来说, IO多路复用编程的第一步,是把通道Channel注册到选择器中,第二步则是通过选择器Selector所提供的事件查询(select)方法,这些注册的通道是否有已经就绪的IO事件(例如可读、可写、网络连接完成等)。由于一个选择器只需要一个线程进行监控,所以,我们可以很简单地使用一个线程,通过选择器去管理多个连接通道。与OIO相比, NIO使用选择器的最大优势:系统开销小,系统不必为每一个网络连接(文件描述符)创建进程/线程,从而大大减小了系统的开销。总之, 通过Java NIO可以达到一个线程负责多个连接通道的IO处理, 这是非常高效的。这种高效,恰恰就来自于Java的选择器组件Selector以及其底层的操作系统IO多路复用技术的支持。

缓冲区(Buffer)

应用程序通过缓冲区与通道建立数据读写交互,Buffer顾名思义:缓冲区,实际上是一个容器,一个连续数组。 Channel提供从文件、网络读取数据的渠道,但是读写的数据都必须经过Buffer。 如下图所示:

在这里插入图片描述

所谓通道的读取,就是将数据从通道读取到缓冲区中;所谓通道的写入,就是将数据从缓冲区中写入到通道中。缓冲区的使用,是面向流进行读写操作的OIO所没有的,也是NIO非阻塞的重要前提。Buffer类是一个抽象类,对应于Java的主要数据类型,在NIO中有8种缓冲区类,分别如下: ByteBuffer、 CharBuffer、 DoubleBuffer、 FloatBuffer、 IntBuffer、 LongBuffer、 ShortBuffer、MappedByteBuffer。 不同的Buffer子类,其能操作的数据类型能够通过名称进行判断,比如IntBuffer只能操作Integer类型的对象。 最常用的是ByteBuffer。如ByteBuffer子类就拥有一个byte[]类型的数组成员final byte[] hb,作为自己的读写缓冲区,数组的元素类型与Buffer子类的操作类型相互对应。那么在接下来的博文中将介绍Buffer具体的用法。

总结

NIO的知识体系就是围绕Buffer(缓冲区)、 Channel(通道)、Selector(选择器)三大核心组件的,下面学习只需要学习这三个核心组件的用法即可,最后将结合代码举例说明!

经典神书推荐:《Java高并发核心编程系列》——尼恩

相关文章:

Java-NIO 开篇(1)

NIO简介 高性能的Java通信,离不开Java NIO组件,现在主流的技术框架或中间件服务器,都使用了Java NIO组件,譬如Tomcat、 Jetty、 Netty、Redis、RabbitMQ等的网络通信模块。在1.4版本之前, Java IO类库是阻塞式IO&…...

VSCode 插件推荐

前言 关于开发用的插件就不做赘述了,网上面有很多文章都做了推荐,本文推荐几个好看的插件。 文件图标主题 Vscode icons Material Icon Theme 字体主题 推荐 One Dark Pro 其他 推荐一个生成好看代码的网址 https://carbon.now.sh/...

摄像部分时序

(1).,后摄像。 (2).,前摄像。 RCAM_TO_LEDDRV_STROBE_EN_CONN表面意思是:后置摄像头到led驱动闪光灯_使能。从时序图中看起来是连接到U17的,发现果然如此。 闪光灯温度检测,是检测闪光灯的温度。所以时序图…...

为什么 Golang Fasthttp 选择使用 slice 而非 map 存储请求数据

文章目录 Slice vs Map:基本概念内存分配和性能Fasthttp 中的 SliceMap性能优化的深层原因HTTP Headers 的特性CPU 预加载特性 结论 Fasthttp 是一个高性能的 Golang HTTP 框架,它在设计上做了许多优化以提高性能。其中一个显著的设计选择是使用 slice 而…...

C#设计模式教程(7):适配器模式

适配器模式的定义 适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间能够相互合作。适配器的作用是解决那些因接口不兼容而不能一起工作的类的问题,它通过包装一个类的接口转换成另一个期望的接口。 适配器模式主要分为两种: 类适配器(Class Ad…...

1818:红与黑【解析】-------深度优先搜索

1818:红与黑 描述 有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。 输入 包括多个数据集合。每个数据集合的第一行…...

实验三 Oracle数据库的创建和管理

🕺作者: 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要&…...

Mysql:重点且常用的 SQL 标签整理

目录 1 <resultMap> 标签 2 <sql> 标签 3 <where> 标签 4 <if> 标签 5 <trim> 标签 6 <foreach> 标签 7 <set> 标签 1 <resultMap> 标签 比如以下代码&#xff1a; <resultMap type"SysCollege" id&qu…...

云锁防火墙编译安装nginx-plugin模块

一般情况下&#xff0c;当用户安装云锁的时候&#xff0c;云锁会自动适配nginx版本&#xff0c;使用我们已经预编译好的包含云锁模块的nginx备份并替换掉您当前系统中使用的nginx。卸载时&#xff0c;会将系统原始nginx文件替换回来。因此&#xff0c;云锁可保护使用nginx搭建的…...

【服务器数据恢复】服务器迁移数据时lun数据丢失的数据恢复案例

服务器数据恢复环境&服务器故障&#xff1a; 一台安装Windows操作系统的服务器。工作人员在迁移该服务器中数据时突然无法读取数据&#xff0c;服务器管理界面出现报错。经过检查发现服务器中一个lun的数据丢失。 服务器数据恢复过程&#xff1a; 1、将故障服务器中所有磁盘…...

6.4.2转换文件

6.4.2转换文件 利用Swf2VideoConverter2可以很方便地将Flash动画(*.swf)转换为其它的视频格式。 1&#xff0e;单击“添加”按钮&#xff0c;在弹出的下拉菜单中选择“添加文件”&#xff0c;在弹出的“Open Swf Files(打开Swf文件)”窗口中选择swf文件(如&#xff1a;那些花…...

智能驾驶新浪潮:SSD与UFS存储技术如何破浪前行?-UFS篇

如果说SSD是赛道上的超级跑车&#xff0c;那UFS更像是专为智能汽车定制的高性能轻量化赛车。UFS采用串行接口技术&#xff0c;像是闪电侠一样&#xff0c;将数据传输的速度推向新高&#xff0c;大幅缩短了系统启动时间和应用程序加载时间&#xff0c;这对追求即时反应的ADAS系统…...

TS 学习笔录(持续更新中)

TS学习笔录 1、TS 数据类型有哪些&#xff1f;2、元组是什么&#xff1f;3、union&#xff08;联合类型&#xff09;& Literal&#xff08;字面量类型&#xff09;?4、any 和 unknown 的区别&#xff1f;5、Object 对象类型&#xff1f;6、type 、interface 、 class 之间…...

RabbitMQ安装和使用

简介 RabbitMQ是一套开源&#xff08;MPL&#xff09;的消息队列服务软件&#xff0c;是由LShift提供的一个Advanced Message Queuing Protocol (AMQP) 的开源实现&#xff0c;由以高性能、健壮以及可伸缩性出名的Erlang写成。所有主要的编程语言均有与代理接口通讯的客户端库…...

使用pyechart创建折线图

import json from pyecharts.charts import Line from pyecharts import options# 首先使用文件打开数据 f_us open(Desktop/python/Project/数据可视化/美国.txt,r,encoding"UTF-8") f_rb open(Desktop/python/Project/数据可视化/日本.txt,r,encoding"UTF-8…...

Vue3+Ts:使用i18n实现国际化与全局动态下拉框框切换语言

Vue3Ts&#xff1a;使用i18n实现国际化与全局动态下拉框框切换语言 一、下载依赖&#xff1a;二、创建ts文件并配置main.ts三&#xff0c;如何使用1.在<template>中使用2.在setup中使用 四、全局下拉框动态切换 一、下载依赖&#xff1a; npm install vue-i18nnex二、创…...

多目标优化中常用的差分进化算法DE【2】

# 多目标优化中常用的进化算法 1、链接一 2、链接二 #后续继续补充多目标的差分进化算法MODE的应用 此链接介绍很详细&#xff0c;此处用来分享学习&#xff0c;后续有问题会继续进行补充。 如果你觉得不错&#xff0c;佛系随缘打赏&#xff0c;感谢&#xff0c;你的支持是…...

游卡:OceanBase在游戏核心业务的规模化降本实践

从 2023 年 9 月测试 OceanBase&#xff0c;到如今 3 个核心业务应用 OceanBase&#xff0c;国内最早卡牌游戏研发者之一的游卡仅用了两个月。是什么原因让游卡放弃游戏行业通用的 MySQL方案&#xff0c;选择升级至 OceanBase&#xff1f;杭州游卡网络技术有限公司&#xff08;…...

LightDB - oracle_fdw 过滤条件下推增强【24.1】

LightDB - oracle_fdw 过滤条件下推增强【24.1】 1. 字符串比较下推1.1 示例 2. 隐式转换下推2.1 示例 3. nvl 和trim 下推3.1 示例 LightDB 在24.1版本对oracle_fdw 的where下推进行了增强&#xff0c;新增对如下两种情况进行下推&#xff1a; 字符串比较下推&#xff0c;如 …...

【计算机网络】HTTP协议以及简单的HTTP服务器实现

文章目录 一、HTTP协议1.认识URL2.urlencode和urldecode3.HTTP协议格式4.HTTP的方法5.HTTP的状态码6.HTTP常见Header7.重定向8.长连接9.会话保持10.基本工具 二、简单的HTTP服务器实现1.err.hpp2.log.hpp3.procotol.hpp4.Sock.hpp5.Util.hpp6.httpServer.hpp7.httpServer.cc8.总…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

【SpringBoot自动化部署】

SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一&#xff0c;能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时&#xff0c;需要添加Git仓库地址和凭证&#xff0c;设置构建触发器&#xff08;如GitHub…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

运行vue项目报错 errors and 0 warnings potentially fixable with the `--fix` option.

报错 找到package.json文件 找到这个修改成 "lint": "eslint --fix --ext .js,.vue src" 为elsint有配置结尾换行符&#xff0c;最后运行&#xff1a;npm run lint --fix...

性能优化中,多面体模型基本原理

1&#xff09;多面体编译技术是一种基于多面体模型的程序分析和优化技术&#xff0c;它将程序 中的语句实例、访问关系、依赖关系和调度等信息映射到多维空间中的几何对 象&#xff0c;通过对这些几何对象进行几何操作和线性代数计算来进行程序的分析和优 化。 其中&#xff0…...

设计模式域——软件设计模式全集

摘要 软件设计模式是软件工程领域中经过验证的、可复用的解决方案&#xff0c;旨在解决常见的软件设计问题。它们是软件开发经验的总结&#xff0c;能够帮助开发人员在设计阶段快速找到合适的解决方案&#xff0c;提高代码的可维护性、可扩展性和可复用性。设计模式主要分为三…...

Jmeter(四) - 如何在jmeter中创建网络测试计划

1.简介 如何创建基本的 测试计划来测试网站。您将创建五个用户&#xff0c;这些用户将请求发送到JMeter网站上的两个页面。另外&#xff0c;您将告诉用户两次运行测试。 因此&#xff0c;请求总数为&#xff08;5个用户&#xff09;x&#xff08;2个请求&#xff09;x&#xff…...