我遇到了与PipedInputStream
和PipedOutputStream
相关的问题,我不知道是否误解了这些类的设计,或者{{1}中的java代码是否存在错误}}
据我所知PipedInputStream.java
和PipedInputStream
实现了一种可用于在两个不同线程之间创建流的机制。生产者线程在PipedOutputStream
中写入内容,而消费者线程在连接的PipedOutputStream
中读取它。有一个内部缓冲区允许缓冲通信。默认情况下,此缓冲区的大小为1024字节。
如果使用者线程读取PipedInputStream
并且缓冲区为空,则线程等待。如果生产者线程写入PipedInputStream
并且缓冲区已满,则线程也会等待。
PipedOutputStream
维护内部缓冲区,PipedInputStream
仅使用PipedOutputStream
中声明的函数。
与PipedInputStream
中的内部(循环)缓冲区相关的所有字段(PipedInputStream
,byte [] buffer
和int in
- 您可以在{{1}中看到}})都声明为int out
。 PipedInputStream.java
使用2个不同的protected
函数注入数据。
所有InputStream都有两个读取版本:PipedInputStream
和PipedInputStream.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 {
(PipeReader
和PipeWriter
的字符版本)声明缓冲区字段和包方法可见性的接收方法(不受保护!)。 Java中的Reader / Writer(自JDK1.1起)比InputStream / OutputStream更新(自JDK1.0起)。
这是PipedInputStream
设计中的一个真正的错误吗?PipedOutputStream
PipedInputStream
可见性是protected
从早期Java版本继承的设计事故?,还是我完全迷失了?
提前致谢。
PD:以下是出现此问题的示例。此程序无法编译(通过上述接收可见性问题)。在这个例子中,我尝试创建一个PipedInputStream
子类,允许在需要时自动扩展缓冲区。所以,如果缓冲区为空,有人试图读取线程等待。但是如果缓冲区已满并且有人尝试写入(使用连接的PipedInputStream
),则线程不会等待,但缓冲区会扩展为存储更多字节。消费者在等待,但生产者却没有。
我有自己的这个例子的功能实现,但我想知道它是否不能作为PipedOutputStream
子类实现。
PipedInputStream
答案 0 :(得分:2)
我认为你误解了管道的用途。管道用于两个不同线程之间的阻止通信。预计写入器的速度将受限于读取器的速度,这意味着管道在内存使用方面是有效的,但是将处理限制为最慢组件的速度。
如果你想要异步写入,你应该看一下使用队列 - java.util.concurrent包中的一个版本应该适合。
答案 1 :(得分:0)
不支持特定用例的API设计(尤其是涉及子类化的用例)可以被描述为“有限”或“受限制”......但是将这称为错误是一种延伸。
如果我们接受可疑的命题 1 ,那么你想要实现的是值得的,那么我认为你的分析是正确的。使用可扩展缓冲区创建管道输入/输出流的版本比修改器不同时更多。
但是......这不是不可能的。您可以通过更大规模的覆盖方法(例如read
和write
方法)或者从头开始实现您想要的目标。
另外需要注意的是,这个(StackOverflow)不是报告Java“错误”或提出增强请求的正确位置。如果您对此非常感兴趣,请尝试开发并提交一份补丁,其中包含您对OpenJDK团队的建议更改。但请记住,任何破坏兼容性的内容(包括与PipedInputStream
和PipedOutputStream
的现有客户子类的兼容性)都可能被拒绝。这可能解释了为什么他们还没有“修复”这个问题!
1 - 正如Barry指出的那样,管道流在设计上受阻。非阻塞版本具有潜在的危险性。