BufferedOutputStream 的 flush 不自动适配多线程——虽方法同步但无法保证业务语义的“写完即刷”,多线程共享时需显式协调 flush,否则易致数据滞留、可见性缺失与顺序错乱,推荐独占流或原子化 write+flush。

BufferedOutputStream 的 flush 机制本身不自动适配多线程场景——它没有内置线程安全设计,flush 触发时机仍严格遵循单线程逻辑:缓冲区满、显式调用 flush()、或 close() 时触发。但在多线程写入时,这些时机容易被干扰或失效,需额外保障。
多线程下 flush 不再“自动可靠”
BufferedOutputStream 的 write() 和 flush() 方法虽是 synchronized,但仅保证单个方法调用的原子性,无法保证业务语义上的“写完即刷”。例如:
- 线程 A 写入 100 字节后未 flush,缓冲区还剩 8KB - 100B;
- 线程 B 紧接着写入 50 字节,count 变为 150,仍未满;
- 此时无任何线程调用 flush(),数据持续滞留在堆内存缓冲区中。
多个线程共用同一个 BufferedOutputStream 实例时,flush 的触发完全依赖开发者显式协调,不存在“某线程写完自动刷给其他线程看”的机制。
关键风险:脏读与丢失不可见
由于底层 FileOutputStream 不支持并发写(会抛 IOException 或导致文件损坏),实际多线程写入通常需外部同步。但即使加了 synchronized 块,仍存在两类典型问题:
立即学习“Java免费学习笔记(深入)”;
- 可见性缺失:线程 A flush() 后,线程 B 无法感知该次刷盘是否完成(除非额外通信);
- 顺序错乱:若多个线程交替写入且各自 flush,可能破坏协议头/校验块等逻辑单元的完整性,比如日志行被切分写入。
推荐做法:避免共享 + 显式语义 flush
不是靠“调用 flush 就安全”,而是靠结构设计规避竞争:
- 每个线程独占一个 BufferedOutputStream(配合独立文件或追加模式文件 + 文件锁);
- 若必须共享流,用 ReentrantLock 控制 write + flush 的原子组合,例如写完一条完整消息后立即 flush();
- 对关键数据(如心跳包、事务标记、JSON 对象末尾),无论线程是否切换,都紧随 write() 调用 flush();
- 禁用 try-with-resources 自动 close 替代中间 flush——close 只在最后发生,无法满足实时性要求。
底层 flush() 在多线程中仍只做一件事
无论多少线程参与,flush() 的行为始终是:
- 检查当前 count > 0;
- 调用底层 out.write(buf, 0, count),再置 count = 0;
- 再调用 out.flush()(如 FileOutputStream 的 flush 实际是空操作,真正落盘靠 write 系统调用)。
它不等待其他线程、不广播状态、不阻塞写入者——只是把“此刻本线程所见的缓冲内容”推下去。所以多线程环境里,flush 是必要但不充分的操作,必须结合同步策略和业务边界使用。


















