BufferedInputStream 的 fill 方法通过调用 InputStream.read(byte[], int, int) 批量读取数据到缓冲区,触发时机为缓冲区为空或不足时,核心是减少 I/O 调用、提升性能;其行为依赖底层流实现,缓冲区大小影响效率,默认 8192 字节。

BufferedInputStream 的 fill 方法通过调用底层 InputStream 的 read(byte[], int, int) 方法一次性读取多字节到内部缓冲区,而不是逐字节读取。它在缓冲区为空或不足时触发,核心目标是减少底层 I/O 调用次数,提升性能。
fill 方法触发时机
当 BufferedInputStream 的 read()、read(byte[]) 等方法发现当前缓冲区中无可用数据(pos >= count),且尚未到达流末尾时,就会调用 fill() 尝试填充缓冲区。
- 缓冲区初始为空(
count == 0) - 已消费完缓冲区所有数据(
pos == count) - 后续读取请求无法从剩余缓冲区满足(例如要读 10 字节,但只剩 2 字节)
fill 方法如何调用底层 InputStream
fill 方法内部会执行以下关键步骤:
- 重置缓冲区指针:
pos = 0 - 尝试用整个缓冲区空间(
buf.length)向底层流读取:count = getIn().read(buf, pos, buf.length) - 如果底层流返回 -1,表示流已结束,
count设为 0 - 若返回 ≥ 0,则
count记录实际读入字节数,缓冲区有效数据范围变为buf[0] ~ buf[count-1]
注意:这里调用的是 InputStream.read(byte[], int, int),不是单字节 read() —— 这正是缓冲设计的关键:一次系统调用尽可能多地搬运数据。
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
底层流的实际行为取决于具体子类
fill 方法本身不关心底层流类型,只依赖其 read(byte[],...) 的契约:
- 对于
FileInputStream:通常触发一次系统调用(如read(2)),从文件描述符批量读取 - 对于
SocketInputStream:尝试从 socket 接收缓冲区拷贝数据,可能受网络包大小和 TCP 窗口影响 - 对于自定义
InputStream:只要正确实现read(byte[],...),fill 就能正常工作
如果底层流的 read(byte[],...) 返回值小于请求长度(比如请求 8192 字节,只读到 1024),fill 仍会接受该结果并更新 count,下次再需填充时继续调用。
缓冲区大小与填充效率的关系
默认缓冲区大小为 8192 字节(JDK 8+),可通过构造函数指定:
- 太小(如 256):fill 频繁触发,I/O 调用增多,抵消缓冲收益
- 太大(如 64KB):内存占用上升,且未必提升性能(受限于底层设备/网络吞吐)
- 合理值(8KB–64KB):平衡内存与系统调用开销,适配多数场景
fill 不会“等待填满”,而是按底层流实际可提供数据量填充——它尊重底层流的非阻塞特性(如 socket 设置了 timeout)和 EOF 语义。

















