pipedinputstream和pipedoutputstream仅支持同jvm内线程间通信,非进程间通信;需显式connect()、分线程读写,否则死锁;阻塞无超时,异常处理脆弱,推荐用blockingqueue等替代方案。

Java里用PipedInputStream和PipedOutputStream能跨线程传数据,但不能跨进程
它俩不是用来做“进程间通信”的,名字里的“Pipe”容易让人误会。实际是线程安全的内存管道,只在同一个JVM内有效,靠内部缓冲区(默认1024字节)和wait/notify机制同步读写线程。
常见错误现象:IOException: Pipe not connected——没调用connect()就直接读写;或者java.io.IOException: Write end dead——写端线程提前退出,读端还在等。
- 必须显式调用
connect(),比如in.connect(out)或构造时传参 - 读写必须在不同线程里跑,否则会死锁(一个线程既写又读,写满缓冲区后阻塞,再也读不到数据)
- 写端异常退出时,读端
read()会返回-1(流结束),不是抛异常
PipedInputStream阻塞读、PipedOutputStream阻塞写,不支持超时
这两个类没有setReadTimeout()或类似机制。一旦连接上,read()会一直等有数据,write()会一直等有空闲缓冲区。这意味着:如果下游线程卡住或没启动,上游会永远挂起。
使用场景有限,典型的是模拟“生产者-消费者”模型,比如解析大文件时边读边处理,避免全量加载到内存。
立即学习“Java免费学习笔记(深入)”;
- 缓冲区满时
write()阻塞,满的判定基于剩余容量,不是绝对字节数(因为可能有未读完的字节) - 构造
PipedInputStream时传int pipeSize可调缓冲区大小,但超过系统页大小(如4KB)意义不大 - 别在Swing/JavaFX主线程里用,会直接卡UI
替代方案更可靠:用BlockingQueue或TransferQueue
如果你只是想在线程间传字节流,PipedInputStream/PipedOutputStream太脆弱。比如写端抛异常没关闭流,读端就永远等下去;又或者GC延迟导致缓冲区堆积,OOM风险高。
更常用的做法是把字节转成byte[]或ByteBuffer,走ArrayBlockingQueue<byte></byte>,控制背压明确,还能加超时、中断支持。
-
LinkedTransferQueue适合高吞吐、低延迟场景,transfer()会阻塞直到消费者接手 - 如果必须保持流接口,可用
PipedInputStream配合Thread.setUncaughtExceptionHandler确保写端崩溃时通知读端 - JDK9+ 可考虑
Flow.Subscriber+SubmissionPublisher做响应式字节流,但复杂度明显上升
调试时怎么看管道状态?没有公开API,只能靠日志和堆栈
这两个类没提供isConnected()、available()之类的方法,内部字段全private。想确认是否连上、缓冲区剩多少、谁在阻塞,只能靠间接手段。
常见错误现象:程序不动了,jstack看到线程停在PipedInputStream.read()或PipedOutputStream.write()——基本就是一端没起来,或已异常终止。
- 启动时加
System.out.println("Connected: " + in.connected)(反射读connected字段,仅调试) - 在写操作前后打日志,比如
log.debug("Writing {} bytes", buf.length),快速定位卡点 - 别依赖
available()判断是否有数据——它返回0不代表没数据,只是当前缓冲区没就绪字节
PipedInputStream本身一句代码都不管。










