博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java NIO buffer源码分析
阅读量:4151 次
发布时间:2019-05-25

本文共 2706 字,大约阅读时间需要 9 分钟。

buffer是个抽象类,被各个原生数据类型的buffer继承,nio中channel是通过buffer进行数据读写操作的

buffer是双向操作,既可以读也可以写,实现buffer读写转化功能的,主要是buffer当中的各个属性字段

线程不安全

  • mark  标记当前索引位置
  • position  下一个可以写或者可以读的索引
  • limit  文档解释:当前不可读或者不可写的索引
  • capacity  当前buffer的容量,会在初始化时进行设置,不可修改,相当于是数组的长度
这几个字段之间的大小关系是mark<=position<=limit<=capacity

如何理解这几个字段具体的含义

比如在初始化一个长度为10的buffer之后,其capacity已经固定了,就是10,此时limit也可以是10,position当前并没有往数组中添加元素,position的索引就是0

buffer.put()添加两个元素之后

capacity的值还是10,(永久不变)

position下一个需要写的索引就是2

此时limit还是等于10,如果需要将已经写入的元素读取出来,也就是由原来的写入,变成读,需要buffer.filp()

这时候position=0, limit=2, capacity=10 

进行元素读取,直到position=2, limit =2 ,capacity=10 不能继续再读下去

当把所有的元素都读取完之后,想要继续写入,再次执行buffer.flip()

position=0 ,limit =2 ,capacity=10 ,从0开始写入 

 
* @return  This buffer */public final Buffer flip() {    limit = position;    position = 0;    mark = -1;    return this;}
 

 这个就是源码中执行flip方法的操作,limit会记录当前读或者写的索引最大值,position从0开始读取,只到position=limit时,读取或者写入结束 

使用NIO读取文件内容时容易出现的一个问题

 
public static void main(String[] args) throws Exception{    FileInputStream inputStream = new FileInputStream("input.txt"); //存在于根目录下的文件    FileOutputStream outputStream = new FileOutputStream("output.txt");    FileChannel fileInputChannel = inputStream.getChannel();    FileChannel fileOutputChannel = outputStream.getChannel();    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);    while (true){        byteBuffer.clear(); //如果将这段代码注释掉,执行结果会出现什么问题       int read =   fileInputChannel.read(byteBuffer);       if(-1 == read){           break;       }       byteBuffer.flip();       fileOutputChannel.write(byteBuffer);    }}
 这里如果while循环中没有byteBuffer.clear() output.txt文件会一直不断地增加,程序处于死循环当中 

原因在于:

第一次进入循环

step1: position=0, limit=capacity,当写入一定数据之后,(假设有5个字节)

position=5,limit=1024,capacity=1024

flip方法后

position=0,limit=5,capacity=1024,

将所有的数据读取完之后,position=5,limit=5,capacity=1024

第二次次进入循环:

read=0

flip方法之后

position=0,limit=5,capacity=1024

数组元素并未被清空,所以会一直读取第一次写入进去的字节,程序进入死循环

----------------------------------------------------------------------------------------

buffer中几个方法

  • clear() 清空当前索引信息,数组信息不会被清空,position=0,limit=capacity ,数据没有被清空,但是不会再重新读取数据了因为position和limit被重置了,找不到末尾标记
  • flip()  由写模式,切换到读取模式
  • rewind()  position清0,可以重复读取之前写入的数据,在rewind被调用之前,已经是读模式了
  • compact()  将未读的数据拷贝到buffer中去,将position指向最后未读的索引后面,limit设置成capacity,准备好写数据,不会覆盖掉之前的数据

clear() 是清空,重新开始写入数据,campact是将未读完的数据,拷贝一部分,保存,然后继续写入数据,会更加浪费内存,clear不能读取到之前写入的数据

在ByteBuffer, slice()方法是将当前ByteBuffer的属性拿过去,直接使用,数组使用的是同一个底层数组,所以不管是之前的ByteBuffer还是slice()方法返回的ByteBuffer,对数组的操作,两个buffer都会有影响

ByteBuffer scattering,gathering

Scattering: channel可以读取内容到一个buffer数组当中,按照数据顺序,会在第一个写满之后,写入下一个

Gathering: 将多个buffer的内容写入到channel当中

什么时候会用到Scattering和Gathering?

     在使用自动义网络协议是,header,body可能是不同的内容,这个时候,可以使用两个不同长度的数据,来进行传递数据,而不需要使用特殊字符来进行分割,或者是截取固定长度的buffer

转载地址:http://gavti.baihongyu.com/

你可能感兴趣的文章
使用三层交换机的ACL实现不同vlan间的隔离
查看>>
php 数据库增删改查例子
查看>>
对渲染管线的调研
查看>>
class
查看>>
第二章作业
查看>>
树链剖分 月下毛景树
查看>>
python函数中的参数类型
查看>>
ubuntu 18.04设置开机自动挂载移动硬盘
查看>>
理解mvn命令
查看>>
python2:输出百分比
查看>>
【C语言】++(a++)的写法是错的
查看>>
mental ray feat. Metallic Car Paint
查看>>
bzoj3038 上帝造题的七分钟2
查看>>
西安80坐标系转北京54坐标系
查看>>
enableEventValidation是干什么的?
查看>>
PHP定时执行任务的实现
查看>>
由一个小Bug推及ie及ff的dom元素差异
查看>>
hive函数大全
查看>>
CBitmap加载图像
查看>>
UITableView加载数据,没有数据,没有网络界面处理
查看>>