是否有PipedInputStream.java设计中的错误或者我误解了它的设计?

时间:2015-02-06 11:20:13

标签: java

我遇到了与PipedInputStreamPipedOutputStream相关的问题,我不知道是否误解了这些类的设计,或者{{1}中的java代码是否存在错误}}

据我所知PipedInputStream.javaPipedInputStream实现了一种可用于在两个不同线程之间创建流的机制。生产者线程在PipedOutputStream中写入内容,而消费者线程在连接的PipedOutputStream中读取它。有一个内部缓冲区允许缓冲通信。默认情况下,此缓冲区的大小为1024字节。

如果使用者线程读取PipedInputStream并且缓冲区为空,则线程等待。如果生产者线程写入PipedInputStream并且缓冲区已满,则线程也会等待。

PipedOutputStream维护内部缓冲区,PipedInputStream仅使用PipedOutputStream中声明的函数。

PipedInputStream中的内部(循环)缓冲区相关的所有字段(PipedInputStreambyte [] bufferint in - 您可以在{{1}中看到}})都声明为int outPipedInputStream.java使用2个不同的protected函数注入数据。

所有InputStream都有两个读取版本:PipedInputStreamPipedInputStream.receive。所有OutputStream都有两个写入版本read()read(byte [], int, int)。它们都有单字节版本和多字节版本。 write(byte b)write(byte [], int, int)具有这些功能。

PipedInputStream使用PipedOutputStream函数将字节注入连接的PipedOutputStream.write(byte b)。此接收函数声明为PipedInputStream.receive(int b),因此您可以重载此函数并拦截从PipedInputStream到连接的protected的任何字节注入。

PipedOutputStream使用PipedInputStream在连接的PipedOutputStream.write(byte b[], int offset, int len)中注入一个字节数组。

我的问题出现了:PipedInputStream.receive(byte [] b, int offset, int len)PipedInputStream的多字节对应部分未被声明为受保护PipedInputStream.receive(byte [], int, int),它具有默认的可见性(包可见性)。因此,您不能重载此函数并拦截从receive(int)到连接的receive(int)的多字节注入。

PipedOutputStream不会调用PipedInputStream。因此,使用PipedInputStream.write(byte b[], int offset, int len)时,重载PipedInputStream.write(int b)无效。

据我了解,receive(int)应为receive(byte [],int, int) PipedInputStream.receive(byte[], int, int)。它的声明:

protected

应该是:

PipedInputStream.receive(int)

synchronized void receive(byte [] b, int off, int len) throws IOException {protected synchronized void receive(byte [] b, int off, int len) throws IOException {PipeReaderPipeWriter的字符版本)声明缓冲区字段和包方法可见性的接收方法(不受保护!)。 Java中的Reader / Writer(自JDK1.1起)比InputStream / OutputStream更新(自JDK1.0起)。

这是PipedInputStream设计中的一个真正的错误吗?PipedOutputStream PipedInputStream可见性是protected从早期Java版本继承的设计事故?,还是我完全迷失了?

提前致谢。

PD:以下是出现此问题的示例。此程序无法编译(通过上述接收可见性问题)。在这个例子中,我尝试创建一个PipedInputStream子类,允许在需要时自动扩展缓冲区。所以,如果缓冲区为空,有人试图读取线程等待。但是如果缓冲区已满并且有人尝试写入(使用连接的PipedInputStream),则线程不会等待,但缓冲区会扩展为存储更多字节。消费者在等待,但生产者却没有。

我有自己的这个例子的功能实现,但我想知道它是否不能作为PipedOutputStream子类实现。

PipedInputStream

2 个答案:

答案 0 :(得分:2)

我认为你误解了管道的用途。管道用于两个不同线程之间的阻止通信。预计写入器的速度将受限于读取器的速度,这意味着管道在内存使用方面是有效的,但是将处理限制为最慢组件的速度。

如果你想要异步写入,你应该看一下使用队列 - java.util.concurrent包中的一个版本应该适合。

答案 1 :(得分:0)

不支持特定用例的API设计(尤其是涉及子类化的用例)可以被描述为“有限”或“受限制”......但是将这称为错误是一种延伸。

如果我们接受可疑的命题 1 ,那么你想要实现的是值得的,那么我认为你的分析是正确的。使用可扩展缓冲区创建管道输入/输出流的版本比修改器不同时更多。

但是......这不是不可能的。您可以通过更大规模的覆盖方法(例如readwrite方法)或者从头开始实现您想要的目标。


另外需要注意的是,这个(StackOverflow)不是报告Java“错误”或提出增强请求的正确位置。如果您对此非常感兴趣,请尝试开发并提交一份补丁,其中包含您对OpenJDK团队的建议更改。但请记住,任何破坏兼容性的内容(包括与PipedInputStreamPipedOutputStream的现有客户子类的兼容性)都可能被拒绝。这可能解释了为什么他们还没有“修复”这个问题!


1 - 正如Barry指出的那样,管道流在设计上受阻。非阻塞版本具有潜在的危险性。