NIO - Buffer
NIO —— Buffer源码分析
Buffer的类结构
底层的基础类是抽象类-Buffer,其中定义了四个变量:capacity(容量),limit(限制),position(位置),mark(标记)
在继承了Buffer后,分别对应Java的基本类型(除了Boolean)产生了7个抽象子类,并且在子类中定义了三个变量:hb(缓存数组),offset,isReadOnly
具体实现类有许多分为三大块:ByteBufferAsXXXX,DirectXXXX(缓冲区在普通内存上),HeapXXXX(缓冲区在JVM的堆上)
那么,要使用Buffer的时候如何进行实例化呢?
需要调用相应类型的Buffer中的静态方法wrap,得到一个实例对象(默认是HeapXXXX)。
在使用wrap进行构造缓冲区的时候,传入的数组在实际构造的时候只是引用了这个数组,因此在缓冲区之外对传入的数组进行操作时,均会影响到缓冲区。
Buffer中的变量描述
NIO的buffer和普通I/O的buffer中的缓存区别在于:NIO的Buffer给缓存数组定义了一系列的操作函数,方便快捷。
capacity(容量):缓存数组的大小,数组是一个final类型的变量,因此容量初始化后便不能更改,如果需要扩容,则需要新建一个buffer对象,将内容put到新对象里面。
limit(限制):第一个不能读取或者写入的索引位置。(可以使用limit()或limit(x)进行获取或修改);默认值为capacity。
position(位置):下一个要写入或者读取的索引位置。(可以使用position()或position(x)进行获取或修改);默认值为0。
mark(标记):在缓冲区中标记一个位置,在reset()时,将position的值改为mark。(可以使用mark()设置当前的position为mark值);默认值为-1;当position或者limit的值小于mark值时,此时mark作废变为-1。
几个变量直接的关系:
正常情况下,四个变量的值均不能为负数。
四个变量的大小顺序:0 <= mark <= position <= limit <= capacity
如果修改的limit值小于当前的position时,position也会相应的改变为limit值。
如果修改的position值大于当前的limit时,会直接抛出异常。
Buffer中提供的操作方法
普通方法:
remaining() —— 获取剩余空间大小(limit-position),可以作为读写时,循环的次数。
isReadOnly() —— 当前缓冲区是否是只读的
isDirect() —— 判断当前缓冲区是否是直接缓冲区;什么是直接缓冲区?正常情况下,buffer的缓冲数组是存放在JVM虚拟机中,这个数组再映射到硬盘中的地址,这会导致吞吐量低,运行效率低,因此,在初始化时可以使用静态方法allocateDirect直接分配直接地址。
put/get方法
get() —— 获取下一个值
get(int index) —— 获取第index位置的值(先判断变量是否合法,并且position值不变)
get(T[] dst, int offset, int length) —— 将length个值保存到从offset索引值开始的dst数组中(先判断变量是否合法)
在验证边界值时:如果是访问dst越界了,会抛出IndexOutOfBoundsException;如果是访问buffer越界了,会抛出BufferUnderflowException。
put(int x) —— 放入一个x值
put(int i, int x) —— 在第i位放入值x(先判断变量是否合法,并且position值不变)
put(T[] dst, int offset, int length) —— 将dst数组从offset开始的length个值存入到缓冲区中(先判断变量是否合法)
put(TBuffer src) —— 将src的缓冲区的remain内容放到当前缓冲区中(先判断变量是否合法)
***所有对数组进行的操作均是使用了System.arraycopy函数。
在验证边界值时:如果是访问src越界了,会抛出IndexOutOfBoundsException;如果是访问buffer越界了,会抛出BufferOverflowException。
因此,在get/put方法中有对数组操作时,一定要用remaining和hasRemaining函数判断剩余空间,在进行分批操作。
putType/getType
将传入的值,按照相应的type类型存储到缓冲区中。
静态方法:
allocate(int capacity) —— 生成一个固定大小的缓冲区(JVM的堆)
allocateDirect(int capacity) —— 生成一个固定大小的直接缓冲区(直接物理内存),虽然在操作的效率上高效,但是缓冲区的创建和销毁会增加消耗。创建是用Unsafe类进行创建,销毁时用虚引用引导GC对内存进行销毁。但不会立马释放
直接缓冲区和非直接缓冲区的比较:
直接缓冲区的put/get操作的效率要高于非直接缓冲区,因为在直接缓冲区中,put/get操作是直接本地系统的操作进行的,效率比通过jvm要高。
final方法:
clear() —— 将缓冲区的状态变为初始状态(limit = capacity;position = 0;mark = -1),并没有将原先的数据引用清除,准备好新一次的写入。
flip() —— 对缓存区进行反转,这个反转是将buffer从写的状态改变为读的状态(limit = position;position = 0;mark = -1)。
hasArray() —— 判断缓冲区底层是否有可用的数组。hb(数组)为null或者是isReadOnly的均返回false。
hasRemaining() —— 判断当前位置(position)和限制位置(limit)之间是否有元素。可以作为读写时,循环的次数。
rewind() —— 修改缓冲区的状态(position = 0;mark = -1),常用于重新读取缓冲区中的内容。
arrayOffset() —— 返回缓冲区中的offset变量,在写入时,起始值的偏移量
对缓冲区的操作
slice(截取) —— 按照缓冲区现在的状态,截取剩余的缓冲区,并创建一个buffer实例,但是底层的数组是共享的,也就是一边修改另一边也会有影响。
duplicate(复制) —— 复制一个状态与现在的一致的buffer实例,但是底层的数组还是共享的。
compact(压缩) —— 将剩余缓冲区压至缓冲区的最前面。
Byte缓冲区类型转换
利用asTypeBuffer可以将ByteBuffer缓冲区转换成相应类型的缓冲区,可视为一种视图(只允许读取,不允许修改)
缓冲区的比较
使用函数equal和compareTo,比较的先后顺序:
- 是否是自身
- 类型是否一致
- remaining是否一致
- position到limit之间的数据是否一致(之前不比较)
本人根据《NIO与Socket编程技术指南》和源码一起进行分析的,如有不正确的地方请进行指正,谢谢!
转载于:https://www.cnblogs.com/hzqingyu/p/9719358.html
NIO - Buffer相关推荐
- java.nio.Buffer flip()方法
碰到java.nio.Buffer flip()方法,不明白是干什么用的,于是就赶快查看中文API,API上面翻译的是:"反转此缓冲区.首先对当前位置设置限制,然后将该位置设置为零.如果已定 ...
- java nio.Buffer的属性变化
java nio.Buffer的属性变化 认识Buffer Channel 提供从文件.网络读取数据的渠道,但是读取或写入的数据都必须经由 Buffer.Buffer,实际上是一个连续数组. 常用的 ...
- mappedbytebuffer_Java NIO Buffer【MappedByteBuffer】概述与FileChannel的联系
" NIO[Non-blocking IO非阻塞式IO],可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情.当数据被写入到缓冲区时,线程可以继续处理它 ...
- java.nio.Buffer 中的 flip()方法
在Java NIO编程中,对缓冲区操作常常需要使用 java.nio.Buffer中的 flip()方法. Buffer 中的 flip() 方法涉及到 Buffer 中的capacity.posi ...
- JAVA NIO - Buffer Channel
2019独角兽企业重金招聘Python工程师标准>>> Buffer和Channel是NIO中的基本对象,凡是涉及到I/O的操作都都会用到Buffer和Channel. Channe ...
- 【Java 网络编程】NIO Buffer 简介 ( 概念 | 数据传输 | 标记 | 位置 | 限制 | 容量 | 标记 | 重置 | 清除 | 翻转 | 重绕 | 链式操作 )
文章目录 I. Buffer 简介 II. Buffer 属性 III. Buffer 数据读写 IV. Buffer 标记 mark() 和重置 reset() V. Buffer 清除 翻转 重绕 ...
- 关于java.nio.Buffer的API
Buffer操作是Java NIO应用开发的基础,以下介绍Buffer操作的相关参数以及操作说明. 浏览全文 转载于:https://www.cnblogs.com/ungshow/archive/2 ...
- Java NIO ———— Buffer 缓冲区详解
引言 缓冲区是一个用于特定基本类型的容器.由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互.数据从通道存 ...
- java rewind()_Java NIO Buffer的clear()、reset()、rewind()、flip()方法的区别
Buffer是一个抽象类,位于java.nio包中,主要用作缓冲区.注意:Buffer是非线程安全类.capacity一旦初始化后就不会改变,其值一直为常量.在使用中我们一般使用Buffer的抽象子类 ...
- NIO Buffer
使用Buffer读写数据一般遵循以下四个步骤: 写入数据到Buffer 调用flip()方法 从Buffer中读取数据 调用clear()方法或者compact()方法 RandomAccessFil ...
最新文章
- python 将ipv4的格式转换
- 微服务--分布式事务的实现方法及替代方案
- 剪辑内核linux,Linux01-Linux编辑内核定制属于自己的内核49
- php报错致命错误203,Centos7 下安装PHP7 phpredis扩展报错解决办法 致命错误:ext/standard/php_smart_str.h...
- 目标检测——模型加速的学习笔记
- android 设置屏幕固定位置,Android 关于dialog的显示位置设置
- android初始化框架alpha,Android Chart 框架 MPAndroidChart 学习笔记1_框架初始化
- 微信小程序学习笔记:选项卡
- 怎么给word文档注音_Word文档怎么添加拼音给文字注音
- mysql题 以下1-7_mysql练习题
- python语音识别库kaldi_Kaldi 使用 DFSMN 训练语音模型
- PNP和NPN磁感应开关有什么区别
- 如何通过 Apple Watch 解锁 Mac !
- centos英文版下如何安装中文语言
- 网络爬虫(网络蜘蛛,网络机器人)与Web安全
- 智能工厂信息系统架构设计-WMS、ERP、MES
- 在CAS Server上增加OAuth2.0协议
- 庄家出货前兆5种情况(风险必看)【转】
- java 素数求和,100-200之间所有素数求和程序代码(二个版本)
- Hetero-ReID 综述
热门文章
- 【数学建模】基于matlab模糊二元决策树【含Matlab源码 038期】
- append追加的html中富文本失效,jquery append 动态添加的元素事件on 不起作用的解决方案...
- redis 验证订单_php+redis消息队列实现抢购功能
- 深度linux磁盘编辑,磁盘管理(分区,格式化,维护,写入,配额)- 磁盘管理 - Deepin深度系统用户手册...
- webservice 安全性 对外_WebService的安全性讨论【身份识别】
- linux终端输出图形_Linux进程关系
- python open函数用法_python中open函数的用法详解
- 大型网站架构系列:负载均衡详解
- Spark 概念学习系列之从物理执行的角度透视spark Job(十七)
- git提交及打标签(tag)流程