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

更新int count变量,fill()函数中getInIfOpen().read(buffer, pos, buffer.length - pos)这行代码的返回值为8192,

执行getBufIfOpen()[pos++] & 0xff,从缓冲区(byte[]数组)中获取第pos(此时pos=0)个索引位置的字节,返回给BufferedInputStream.class::read()函数的调用方,并更新pos的值为pos+=1;
之后,每次调用BufferedInputStream.class::read()函数时,都不会再执行fill()函数了,并且当pos=4096时,执行了bis.mark(8192),设置marklimit=8192,markpos=pos=4096。

直到pos=8192时,执行BufferedInputStream.class::read()函数才会再次执行fill()函数,本次填充缓冲区(byte[]数组)的过程如下:
①、执行fill()函数的如下代码片段(标题3.1.4也会复用之后的逻辑)

...省略部分代码... else if (pos >= buffer.length) if (markpos > 0) { //场景一:pos>=缓冲区(byte[]数组)的长度并且markpos >0 int sz = pos - markpos; //只把缓冲区(byte[]数组)中[markpos,pos) 索引区间的元素复制到缓冲区(byte[]数组)[0,pos-markpos)索引区间 System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz;//设置pos=pos-markpos markpos = 0;//设置markpos=0 } ...省略部分代码...

先把缓冲区(byte[]数组)中[4096,8192) 索引区间的元素复制到缓冲区(byte[]数组)[0,4096)索引区间,如下所示:

再更新pos=4096,markpos = 0;
②、然后从被装饰的输入Stream(FileInputStream)读取第8193~12286个字节到缓冲区(byte[]数组)的[4096,8192)索引位置(左闭右开,不包括byte[]数组的第8192个索引位置),并返回读取的字节数量。如下所示:

然后更新count,此时count = n + pos=4096+4096=8192,pos=4096,markpos = 0
③、执行getBufIfOpen()[pos++] & 0xff,从缓冲区(byte[]数组)中获取第pos(此时pos=4096)个索引位置的字节,返回给BufferedInputStream.class::read()函数的调用方,并更新pos的值为pos+=1;
之后,每次调用BufferedInputStream.class::read()函数时,都不会再执行fill()函数了,直到pos=8192时(此时,count = 8192,markpos=0),执行BufferedInputStream.class::read()函数才会再次执行fill()函数,后续过程分为以下2种情景:

  • 情景一,如上伪代码bis.mark(8192),设置marklimit=8192<=缓冲区(byte[]数组)的长度

①、执行fill()函数的如下代码片段:

...省略部分代码... } else if (buffer.length >= marklimit) {//场景二:pos>=缓冲区(byte[]数组)的长度并且缓冲区(byte[]数组)的长度>= marklimit markpos = -1; //设置markpos = -1 pos = 0; //设置pos = 0 } ...省略部分代码...

先更新pos = 0,markpos = -1;然后从被装饰的输入Stream(FileInputStream)读取第12287~20000个字节到缓冲区(byte[]数组)的[0,7914)索引位置(左闭右开,不包括byte[]数组的第7914个索引位置),并返回读取的字节数量。如下所示:

此时,被装饰的输入Stream(FileInputStream)中的字节被全部读取完毕,被装饰的输入Stream(FileInputStream)为空。
②、更新int count变量,fill()函数中getInIfOpen().read(buffer, pos, buffer.length - pos)这行代码的返回值为7914,count=7914+0=7914;
③、执行getBufIfOpen()[pos++] & 0xff,从缓冲区(byte[]数组)中获取第pos(此时pos=0)个索引位置的字节,返回给BufferedInputStream.class::read()函数的调用方,并更新pos的值为pos+=1;
之后,每次调用BufferedInputStream.class::read()函数时,都不会再执行fill()函数了,直到pos=7914时,执行BufferedInputStream.class::read()函数才会再次执行fill()函数,过程如下:
①、因为markpos = -1,所以更新pos=0,count=0,缓冲区(byte[]数组)中的数据如下:

此时,由于被装饰的输入Stream(FileInputStream)中的字节被全部读取完毕,fill()函数中getInIfOpen().read(buffer, pos, buffer.length - pos)这行代码的返回值为0,无法更新count,结束fill()函数的调用
②、执行return -1,返回给BufferedInputStream.class::read()函数的调用方;

  • 情景二,改变上面的伪代码bis.mark(8192),而是设置marklimit>缓冲区(byte[]数组)的长度(只要是大于8192的任何值都可以),比如bis.mark(16384)

①、执行fill()函数的如下代码片段,

...省略部分代码... } else {//场景四:pos>=缓冲区(byte[]数组)的长度并且不满足场景一、二、三时,将缓冲区(byte[]数组)扩容 //如果pos<2147483639/2,则新缓冲区(byte[]数组)的长度nsz=pos*2,否则新缓冲区(byte[]数组)的长度nsz=2147483639 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit;//当新缓冲区(byte[]数组)的长度nsz>marklimit,新缓冲区(byte[]数组)的长度nsz=marklimit byte nbuf[] = new byte[nsz];//新建一个新缓冲区(byte[]数组) System.arraycopy(buffer, 0, nbuf, 0, pos);//将老缓冲区(byte[]数组)中[0,pos)索引区间的元素复制到新缓冲区(byte[]数组)[0,pos)索引区间 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {//通过CAS(Compare-And-Swap)操作来原子地更新buf变量 // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; throw new IOException("Stream closed"); } buffer = nbuf;//新缓冲区(byte[]数组)创建完毕 } ...省略部分代码...

先扩大缓冲区(byte[]数组)的长度到16384(扩大前缓冲区长度为8192),然后将旧缓冲区(byte[]数组)中的内容移动到新缓冲区(byte[]数组)对应的索引位置上,如下所示:

然后通过CAS(Compare-And-Swap)操作来原子地更新buf变量的引用。
②、然后从被装饰的输入Stream(FileInputStream)读取第12287~20000个字节到新缓冲区(byte[]数组)的[8192,16106)索引位置(左闭右开,不包括新byte[]数组的第16106个索引位置),并返回读取的字节数量。如下所示:

此时,被装饰的输入Stream(FileInputStream)中的字节被全部读取完毕,被装饰的输入Stream(FileInputStream)为空。
③、更新int count变量,fill()函数中getInIfOpen().read(buffer, pos, buffer.length - pos)这行代码的返回值为7914,count=7914+pos=16106;
④、执行getBufIfOpen()[pos++] & 0xff,从缓冲区(byte[]数组)中获取第pos(此时pos=8192)个索引位置的字节,返回给BufferedInputStream.class::read()函数的调用方,并更新pos的值为pos+=1;
之后,每次调用BufferedInputStream.class::read()函数时,都不会再执行fill()函数了,直到pos=16106时,执行BufferedInputStream.class::read()函数才会再次执行fill()函数,过程如下:
①、因为markpos = 0,不会设置pos=0,也不会再执行场景一、场景二、场景三、场景四(标题三源码中的注释)、新缓冲区(byte[]数组)中的数据如下:

此时,由于被装饰的输入Stream(FileInputStream)中的字节被全部读取完毕,fill()函数中getInIfOpen().read(buffer, pos, buffer.length - pos)这行代码的返回值为0,无法更新count变量,结束fill()函数的调用
②、执行return -1,返回给BufferedInputStream.class::read()函数的调用方;

3.1.3、如果在多次执行BufferedInputStream.class::read()函数之后执行过mark()函数

如果在很多次调用read()函数之中调用了mark(8192)函数,如下(伪代码):

InputStream is = new FileInputStream("D:\\nio-data.txt"); BufferedInputStream bis = new BufferedInputStream(is); int bytesRead; while ((bytesRead = bis.read()) != -1) { //处理读取到的字节bytesRead } bis.mark(8192);//设置marklimit=8192,markpos=pos=0

那么,BufferedInputStream对象中的缓冲区(byte[]数组)的长度为8192(缓存8KB字节),上述代码的执行过程如下(假设被装饰的输入Stream(FileInputStream)中有10000个字节):
参考标题3.1,与标题3.1不同的是,最后执行bis.mark(8192);,设置marklimit=8192,markpos=pos=0。

3.1.4、如果在多次执行BufferedInputStream.class::read()函数之中执行过mark()函数和reset()函数

如果在很多次调用read()函数之中调用了mark(8192)函数,然后又调用了reset()函数,如下(伪代码):

InputStream is = new FileInputStream("D:\\nio-data.txt");//假设该被装饰的输入Stream(FileInputStream)中有20000个字节 BufferedInputStream bis = new BufferedInputStream(is); int bytesRead; int i = 0; while ((bytesRead = bis.read()) != -1) { if(++i==4096){ bis.mark(8192);//设置marklimit=8192,markpos=pos=4096 } //处理读取到的字节bytesRead if(i==8196){ bis.reset();//当pos=8196时,执行reset()函数,设置pos=markpos=0 } }

那么,BufferedInputStream对象中的缓冲区(byte[]数组)的长度为8192(缓存8KB字节),上述代码的执行过程如下(假设被装饰的输入Stream(FileInputStream)中有20000个字节):
①、pos=count=0,缓冲区(byte[]数组)中还没有填充任何数据,执行fill()函数,然后将被装饰的输入Stream(FileInputStream)中的字节读取到缓冲区(byte[]数组)的[0,8192)索引位置(左闭右开,不包括byte[]数组的第8192个索引位置),并返回读取的字节数量。如下所示:

http://www.jsqmd.com/news/1093123/

相关文章:

  • D3KeyHelper终极指南:暗黑3智能游戏自动化与按键管理解决方案
  • BGP路由反射器实战:从反射簇设计到防环机制的部署与验证
  • 量子LDPC码波束搜索解码器:原理、优化与应用
  • 考验AI的“自我“-AI对《红楼梦》后40回的改写(29)
  • 内蒙古经销商线上获客怎么做?呼和浩特专业 GEO 获客 + 短视频推广服务商推荐
  • 官宣邀约|7 月慕尼黑上海电子展,中国星坤 × 云汉芯城联合亮相 N2-609,恭候莅临!
  • 面了几个程序员转AI Agent方向,真的崩溃…
  • OV SSL证书一年费用多少?单域名、多域名和通配符价格怎么选
  • HarmonyOS APP《画伴梦工厂》开发第10篇:相册选择与 PhotoViewPicker——从相册导入图片
  • 使用示例示例(1)使用方法一全局函数调用,其余使用结构体方法调用。
  • React Virtual DOM 性能优化实践
  • 信号链路——从采样电阻到电流数值
  • 关于算法性能的理论极限与工程突破路径的技术7
  • 基于matlab模拟直导线中电流感应的电磁场
  • 从调试失败到上线交付:一位资深架构师的ChatGPT API Python集成手记(含企业级重试/降级/监控完整链路)
  • Java的java.lang.foreign.MemorySegment内存访问模式与缓存友好性优化
  • gomonkey
  • 3步搞定缠论分析:开源ChanlunX通达信插件终极指南
  • 苹果4.3 App 为什么建议先做好核心功能,再持续迭代?一次真实项目的经验总结
  • 80%的学术科研党都在用 Gemini 3.5 这样输出高质量的Discussion!
  • python生成图表
  • 独立开发者怎么赚钱?源码销售、SaaS订阅、商业授权,我各试了一遍
  • SpiderFoot实战指南:自动化OSINT与攻击面管理
  • MSPM0 H-Series I2C模块深度解析:从控制器/目标模式到低功耗与DMA优化
  • 剑指offer-78、求平⽅根
  • 软件库存管理中的补货策略制定
  • 口碑好的抗衰项目直销厂商
  • ROS话题通信实战:从原理到完整实现
  • 无法强制安装 pyinstaller-hooks-contrib
  • Agent编排的核心挑战指令与内容分离剪贴板法则的实践与思考