当前位置: 首页 > 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.gsyq.cn/news/1605083.html

相关文章:

  • D3KeyHelper终极指南:暗黑3智能游戏自动化与按键管理解决方案
  • 量子LDPC码波束搜索解码器:原理、优化与应用
  • BGP路由反射器实战:从反射簇设计到防环机制的部署与验证
  • 考验AI的“自我“-AI对《红楼梦》后40回的改写(29)
  • OV SSL证书一年费用多少?单域名、多域名和通配符价格怎么选
  • 信号链路——从采样电阻到电流数值
  • 从调试失败到上线交付:一位资深架构师的ChatGPT API Python集成手记(含企业级重试/降级/监控完整链路)
  • 口碑好的抗衰项目直销厂商
  • MSPM0 H-Series I2C模块深度解析:从控制器/目标模式到低功耗与DMA优化
  • 无法强制安装 pyinstaller-hooks-contrib
  • TAS5711数字音频放大器:从I2S到PWM的完整开发指南
  • Agent编排的核心挑战指令与内容分离剪贴板法则的实践与思考
  • 实战ModSecurity WAF:从DVWA靶场到自定义SQL注入防御规则
  • go 数字人Coze智能体
  • 卡梅德生物技术快报|羊驼纳米抗体文库筛选实操全流程:天然 / 合成文库构建与淘选参数汇总
  • AI数字人平台热门十三问|必火AI数字人全维度专业解答
  • 如何高效优化电子书阅读体验:Kindle Comic Converter的完整漫画转换方案
  • 从 0 开始学 Python:装好环境,写一下demo实例
  • GPU硬件故障排查终极指南:5分钟完成显卡内存稳定性检测
  • 收藏!小白程序员必看:如何将大模型Agent从Demo成功落地工程实践?
  • Lean 4实战指南:5个步骤掌握下一代定理证明编程语言
  • Vibe Coding:说人话就能做软件,超简单开发流程全讲明白
  • XSS防御实战:从同源策略到CSP的纵深安全体系构建
  • Kafka2.4-Windows安装教程
  • 02 状态(State)
  • 工程项目过程留痕管理的3个断点与5款软件选型对比
  • Matlab 麻雀优化双向长短期记忆网络(SSA-BILSTM)的时间序列预测(时序)
  • 京东抢购助手终极指南:免费开源工具实现自动化抢单
  • 别一上来就看复杂插件:先用 Delay看懂一个最小 VM 插件是怎么接进系统的
  • 小白程序员必看!收藏这篇,轻松入门大模型工具调用与Function Calling