Java NIO (一)简介(备份)

1 NIO简介

        在1.4版本之前,Java NIO类库是阻塞IO,从1.4版本开始,引进了新的异步IO库,被称为Java New IO类库,简称为Java NIO。New IO类库的目的 就是要让Java支持非阻塞IO。

        Java NIO类库包含三个核心组件:

        1、Channel(通道)

        2、Buffer(缓冲区)

        3、Selector(选择器)

        理解了上一章高并发IO底层原理,大家会马上识别出来Java NIO属于第三种模型——IO多路复用模型。只不过,Java NIO组件提供了统一的API,为大家屏蔽了底层的操作系统的差异。

        本章,会对上面3个组件展开详细介绍。首先看一下Java NIO和OIO的简单对比。

1.1 NIO和OIO的对比

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

        1、OIO是面向流的,NIO是面向缓冲区的。在一般的OIO操作中,面向字节流或字符流的IO操作总是以流式的方式顺序地从一个流(Stream)中读取一个或多个字节,因此,我们不能随意改变读取指针的位置。在NIO操作中则不同,NIO中引入了Channel和Buffer的概念。面向缓冲区的读取和写入只需要从通道读取数据到缓冲区中,或将数据从缓冲区写入到通道中。NIO不像OIO那样顺序操作,它可以随意读取Buffer中任意位置的数据。

        2、OIO的操作是阻塞的,而NIO是非阻塞的。OIO操作时,例如调用一个read方法读取一个文件的内容,调用read的线程就会被阻塞,直到read操作完成。在NIO模式中,当调用read方法时,如果此时有数据,则read读取数据并返回,如果此时没有数据,则read也返回直接返回,而不会阻塞当前线程。

        3、OIO没有选择器(Selector)的概念,而NIO有选择器的概念。NIO的实现是基于底层选择器的系统调用的,所以NIO需要底层操作系统提供支持,而OIO不需要选择器。

1.2 通道

        在OIO中,同一个网络连接会关联两个流:一个是输入流(Input Stream),另一个是输出流(Output Stream)。Java应用程序通过这两个流不断地进行输入和输出的操作。

        在NIO中,一个网络连接使用一个通道表示,所有NIO的IO操作都是通过连接通道完成的。一个通道类似于OIO中两个流的结合体,既可以从通道读取数据,也可以向通道写入数据。

1.3 选择器

        首先回顾一下前面介绍的基础知识——IO多路复用(高并发IO底层原理)指的是一个进程/线程可以同时监视多个文件描述符(含socket连接),一旦其中的一个或多个文件描述符可读或者可写,该监听进程/线程就能够进行IO就绪事件的查询。

        在Java应用层面,如何实现对多个文件描述符的监视呢?需要用到一个非常重要的Java NIO组件——选择器。选择器可以理解为一个IO事件的监听与查询器。通过选择器,一个线程可以查询多个通道的IO事件的就绪状态。

        从编程实现维度来说,IO多路复用变成的第一步是把通道注册到选择器中,第二步是通过选择器所提供的事件查询(select)方法来查询这些注册的通道是否有已经就绪的IO事件(例如可读、可写、网络连接完成等)。

        由于一个选择器只需要一个线程进行监控,因此我们可以很简单地使用一个线程,通过选择器去管理多个连接通道。

        与OIO相比,NIO使用选择器的最大优势就是系统开销小。系统不必为每一个网络连接(文件描述符)创建进程/线程,从而大大减少了系统的开销。总之,一个线程负责多个连接通道的IO处理是非常高效的,这种高效来自Java的选择器组件Selector及其底层的操作系统IO多路复用技术的支持。

1.4 缓冲区

        应用程序与通道的交互主要是进行数据的读取和写入。为了完成NIO的非阻塞读写操作,NIO准备了第三个重要的组件——Buffer。所谓通道的读取,就是将数据从通道读取到缓冲区中;通道的写入,就是将数据从缓冲区写入通道中。缓冲区的使用是面向流进行读写操作的OIO所没有的,也就是NIO非阻塞的重要前提和基础之一。

2 Buffer类

        Buffer类是一个抽象类,对应于Java的主要数据类型。在NIO中,有8种缓冲区类,分别是ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer、MappedByteBuffer。前7种Buffer类型覆盖了能在IO中传输的所有Java基本数据类型,第8种类型是一种专门用于内存映射的ByteBuffer类型。不同的Buffer子类可以操作的数据类型能够通过名称进行判断,比如IntBuffer只能操作Integer类型的对象。

        实际上,使用最多的是ByteBuffer(二进制字节缓冲区)类型,后面的章节会看到它的具体使用。

2.1 Buffer类的重要属性

        Buffer的子类会拥有一块内存,作为数据的读写缓冲区,但是读写缓冲区并没有定义在Buffer基类中,而是定义在具体的子类中。例如,ByteBuffer子类就拥有一个byte[]类型的数组成员

final byte[] hb; 

可以作为自己的读写缓冲区,数据的元素类型与Buffer子类的操作类型相对应。为了记录读写的状态和位置,Buffer类额外提供了一些重要的属性,其中有三个重要的成员属性:capacity(容量)、position(读写位置)和limit(读写的限制)。

        1、capacity属性

        Buffer类的capacity属性表示内存容量的大小。一旦写入的对象数量超过了capacity,缓冲区就满了,不能在写入。capacity属性一旦初始化,就不能再改变。原因是什么呢?Buffer类的对象在初始化时会按照capacity分配内部数组的内存,在数据内存分配好之后,它的大小就不能改变了。前面讲到,Buffer类是一个抽象类,Java不能直接用来创建对象。在具体使用的时候,必须使用Buffer的某个子类,例如DoubleBuffer子类,该子类能写入的数据类型是double,如果在创建实例时,其capacity是100,那么最多可以写入100个double类型的数据。

        【注意】capacity不是指内部的内存块byte[]数组的字节数量,而是指能写入的数据对象的最大限制数量。

        2、position属性

        position表示当前的位置。position属性的值与缓冲区的读写模式有关,在不同的模式下,position属性值的含义是不同的,在缓冲区进行读写的模式改变时,position值会进行相应的调整。

        在写模式下,position值的变化规则如下:

        (1)在刚进入写模式时,position值为0,表示当前的写入位置从头开始。

        (2)每当一个数据写到缓冲区后,position就会向后移动到下一个可写的位置。

        (3)初始的position值为0,最大可写值为limit-1。当position值达到limit时,缓冲区就已经无可用空间写入了。

        在读模式下,position值的变化规则如下:

        (1)当缓冲区刚开始进入读模式时,position会被重置为0.

        (2)当从缓冲区读取时,也是从position位置开始读。读取数据后,position向前移动到下一个可读的位置。

        (3)在读模式下,limit表示可读数据的上线。position的最大值为最大可读上线limit,当position达到limit时表示缓冲区已经无数据可读。

        Buffer的读写模式具体如何切换呢?当新建了一个缓冲区实例时,缓冲区处于写模式,这时可以写入数据。在数据写入完成后,如果要从缓冲区读取数据,就要进行模式的切换,可以调用flip()方法将缓冲区变成读模式,flip为翻转的意思。再从写模式到读模式的翻转过程中,position和limit属性值会进行调整,具体的规则是:

        (1)limit属性被设置成写模式时的position值,表示可以读取的最大数据位置。

        (2)position由原来的写入位置变成新的可读位置,也就是0,表示可以从头开始读。

        3、limit属性

        limit属性表示可以写入或读取的数据最大上限,其属性值的具体含义也与缓冲区的读写模式有关。在不同的模式下,limit值的含义是不同的,具体分为以下两种情况。

        (1)在写模式下,limit属性值的含义为可以写入的数据最大上限。在刚进入写模式时,limit的值会被设置成缓冲区的capacity值,表示可以一直将缓冲区的容量写满。

        (2)在读模式下,limit值的含义为最大能从缓冲区读取多少数据。

        一般来说,在进行缓冲区操作时是先写入再读取。当缓冲区写入完成后,就可以开始从Buffer读取数据,调用flip()方法,这时limit的值也会进行调整。具体如何调整呢?将写模式下的position值设置成读模式下的limit值,也就是说,将之前写入的最大数量作为可以读取数据的上限值。

        Buffer在翻转时的属性值调整主要涉及position,limit两个属性,但这种调整比较微妙,不太好理解,下面举例说明:

        首先,创建缓冲区。新创建的缓冲区处于写模式,其position值为0,limit值为最大容量capacity。

        然后,向缓冲区写数据。每写入一个数据,position向后面移动一个位置,也就是position的值加1。这里假定写入了5个数,当写入完成后,position的值为5.

        最后,使用flip()方法将缓冲区切换到读模式。limit的值会先被设置成写模式的position值,所以新的limit的值是5,表示可以读取数据的最大上限是5.之后调整position值,新的position会被重置为0,表示可以从0开始读。

        缓冲区切换到读模式后就可以从缓冲区读取数据了,一直到缓冲区的数据读取完毕。

        除了以上capacity、limit、position三个重要的成员属性外,Buffer还有一个比较重要的标记属性:mark(标记)属性。该属性的大致作用是:在缓冲区操作过程中,可以将当前的position值临时存入mark属性中,需要的时候,再从mark中取出暂存的标记值,恢复到position属性中,重新从position位置开始处理。

        下面用表总结一下Buffer类的四个重要属性。

508f47c9644b4ddcbb2f80038a3a60a5.jpeg

 

       

   

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AGV磁导航传感器CNS-MGS-160N安装与调试方法与注意事项

AGV磁导航传感器CNS-MGS-160N通过上位机给传感器下发岔路选择指令,传感器即⾃动屏蔽⾮选择⽅向的磁条,使AGV平滑过弯⽆抖动,可通过配置软件设置传感器的检测灵敏度,适应不同的安装⾼度下的检测要求,其通过输出1mm⾼精度…

行测:国考省考行测:语句表达,位置分析,语句分析,语句填空

国考省考行测:语句表达 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能,附带行测和申论,而常规国考省考最重要的还是申论和行测,所以大家认真准备吧,我讲一起屡屡申论和行测的重要知识点 遇到…

STM32 CubeIDE 使用 CMSIS-DAP烧录 (方法2--外部小工具)

前言: 本篇所用方法,需要借助一个外部的工具小软件。 优点:烧录更稳定; 缺点:不能在线仿真调试。 下面链接,是另一种方法:修改CubeIDE调试文件。能在CubeIDE直接烧录、仿真,但不稳定。…

人工智能在数据安全中的应用场景

场景一:数据资产梳理 数据资产梳理是数据安全的基础。知道企业究竟有多少数据,这些数据在哪里?有哪些类型的数据?其中哪些是敏感数据?这些数据的敏感等级分别是什么?只有明确了保护的目标,才能…

浅析企业云性能监控的关键作用

企业云性能监控是一项关键的IT管理活动,它旨在实时追踪、分析和优化企业在云环境中的应用程序和系统性能。云性能监控涉及到监测各个层面的云服务,从基础设施到应用程序,以确保企业能够在云环境中实现高效、可靠和稳定的运行。以下是企业云性…

20. 从零用Rust编写正反向代理,四层反向代理stream(tcp与udp)实现

wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子 项目地址 gite: https:…

transbigdata笔记:可视化

1 可视化轨迹 transbigdata.visualization_trip(trajdata, col[Lng, Lat, ID, Time], zoomauto, height500) 例子见transbigdata 笔记:官方文档案例1(出租车GPS数据处理)-CSDN博客 2 可视化od transbigdata.visualization_od(oddata, col…

深入解析JavaScript中的变量作用域和闭包

🧑‍🎓 个人主页:《爱蹦跶的大A阿》 🔥当前正在更新专栏:《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 JavaScript作为一门解释执行的脚本语言,其变量作用域与传统编译型语言…

第二证券:抢占技术前沿 中国光伏企业结伴“走出去”

2024年新年前后,光伏职业分外忙碌。据证券时报记者不完全统计,晶澳科技、华晟新动力、高测股份、华民股份等多家企业宣告新建项目投产,安徽皇氏绿能等企业的项目也迎来设备安装的重要节点。 证券时报记者采访多家企业的负责人后了解到&#…

3.goLand基础语法

目录 概述语法for常量与变量数组切片 slice切片问题问题1问题2 Make 和 New结构体和指针结构体标签 结束 概述 从 java 转来学 go &#xff0c;在此记录&#xff0c;方便以后翻阅。 语法 for package mainimport "fmt"func main() {for i : 0; i < 3; i {fmt.…

这可能是最全面的Java并发编程八股文了

内容摘自我的学习网站&#xff1a;topjavaer.cn 分享50道Java并发高频面试题。 线程池 线程池&#xff1a;一个管理线程的池子。 为什么平时都是使用线程池创建线程&#xff0c;直接new一个线程不好吗&#xff1f; 嗯&#xff0c;手动创建线程有两个缺点 不受控风险频繁创…

开发实践6_缓存^中间件

以下学习 朔宁夫 开发工程师 课程。 缓存可提高程序响应速度。数据库缓存(可过期)/ Redis缓存(Key:Value)/ Memcacheed缓存/ 程序层缓存。 一 缓存 1. 数据库缓存 创建缓存数据表 // python manage.py createcachetable cache_table setting // # 缓存配置 CACHES {def…

精品基于Uniapp+Springboot宠物用品服务销售管理系统App

《[含文档PPT源码等]精品基于UniappSpringboot宠物管理系统App》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 后台框架&#xff1a;springboot、ssm 安卓…

js日期排序(使用sort)

根据日期进行排序&#xff0c;也可以根据number类型的大小来进行排序 按日期排序的函数 let data [{id: 2,time: 2019-04-26 10:53:19},{id: 4,time: 2019-04-26 10:51:19}, {id: 1,time: 2019-04-26 11:04:32}, {id: 3,time: 2019-04-26 11:05:32} ] //property是你需要排序…

geemap学习笔记048:光谱变换

前言 Earth Engine中有多种光谱变换方法。其中包括图像上的实例方法&#xff0c;例如 normalizedDifference()、unmix()、rgbToHsv() 和 hsvToRgb()。 1 导入库并初始化 import ee import geemapee.Initialize()2 全色图像锐化(Pan sharpening) Map geemap.Map(center[40,…

计算机二级Python基本排序题-序号43(补充)

1. 在一组单词中&#xff0c;查找出所有长度最长的单词&#xff0c;如果给定的一组单词是&#xff1a;“cad” ,“VB”.“Python” ,“MATLAB” , “hel1o” , “world” 则输出结果为&#xff1a;the longest words are: Python MATLAB def proc(strings): …

unique()函数

这篇博客是本人在学习算法中遇到的一个常用的函数&#xff0c;记录分享给大家 注意 &#xff1a;unique&#xff08;&#xff09;函数是删除相邻的重复元素&#xff0c;并且返回的是去重范围后的第一个元素的地址&#xff0c;左闭右开 #include <bits/stdc.h> using na…

SV-8004VP 网络对讲求助话筒,4个自定义按键

SV-8004VP网络对讲求助话筒&#xff0c;4个自定义按键 SV-8004VP是一款4按键求助对讲话筒&#xff0c;具有10/100M以太网接口&#xff0c;支持G.711音频编解码&#xff0c;其接收SIP网络的音频数据&#xff0c;实时解码播放&#xff0c;还配置了麦克风输入和扬声器输出。 SV-…

༺༽༾ཊ—设计-七个原则-模式—ཏ༿༼༻

第一原则&#xff1a;单一职责 一个类只负责一个功能领域中的相应职责&#xff1b; 接下来我们举一个代码例子&#xff0c;主要的功能实现是&#xff1a; 在主函数中运行调用描边工具和填充工具画矩形与圆形 首先写一个圆形类&#xff0c;里面只有一个方法用来返回string类型…

创意交融:集成自定义报表和仪表盘设计器,实现图标替换

前言 在现代数据分析领域&#xff0c;随着对报表和数据分析的需求不断增长&#xff0c;市场上涌现了许多嵌入式报表工具。这些工具能够与企业现有的OA、ERP、MES、CRM等应用系统深度集成&#xff0c;实现对业务数据的自助式分析。然而&#xff0c;在实际应用中&#xff0c;不同…