2012-02-28 178 views
8

我在SO上看到两个答案,声称由Java提供的PipedInputStreamPipedOutputStream类有缺陷。但他们没有详细说明他们有什么问题。他们真的有缺陷,如果是这样,以什么方式?我目前正在写使用它们的一些代码,所以我想知道我是否采取了错误的转弯。PipedInputStream/PipedOutputStream的缺陷

One answer说:

PipedInputStreamPipedOutputStream被破坏(与关于线程)。他们假设每个实例都绑定到一个特定的线程。这是奇怪的。

对我来说,这似乎既不离奇也不碎裂。也许作者也有其他一些缺陷?

Another answer说:

在实践中,他们都最好避免。我已经在13年内使用了他们一次,我希望我没有。

但是,笔者不记得什么问题了。


就像所有的类,特别是在多线程中使用的类一样,如果你滥用它们,你将会遇到问题。所以我不认为"write end dead" IOExceptionPipedInputStream可以抛出一个瑕疵(无法close()连接PipedOutputStream是一个错误,请参阅Daniel Ferbers的文章Whats this? IOException: Write end dead欲知更多信息)。还有其他什么声称的缺陷?

+0

这个http://stackoverflow.com/questions/484119/why-doesnt-more-java-code-use-pipedinputstream-pipedoutputstream种类覆盖它。它们并不是真正的“缺陷”,只是有点棘手,通常也是一种符号代码味道,如果你100%肯定你需要它们,而且在设计中没有错误,那么使用它们就没有真正的问题...... – TC1 2012-02-28 14:42:24

+1

快速查看我想使用的一个。它至少是“特色下”,因为阅读线程并不真正等待写入线程写入完整的读取请求,并且在编写器关闭它时等待EOF异常。它具有非常原始的线程处理和同步,并且要求缓冲区与最大读取请求一样大。 – peterk 2013-03-27 00:17:59

回答

10

他们不是有缺陷的。在多线程使用

与所有类,特别是类,如果滥用它们,你将有问题。 PipedInputStream可能抛出的不可预知的“写入结束死亡”IOException不是缺陷(未能连接close()连接的PipedOutputStream是一个错误;请参阅Daniel Ferbers的文章Whats this? IOException: Write end dead以获取更多信息)。

+0

我想就您最近遇到的问题发表意见。你可以看一下吗? http://stackoverflow.com/questions/21884188/android-pipedinputstream-messes-up-data – fabian 2014-02-19 19:03:16

3

我已经很好地将它们用在了我的项目中,它们对于修改流中的流并将它们传递出去非常宝贵。唯一的缺点似乎是的PipedInputStream有过短暂的缓冲(1024左右)和我的OutputStream围绕8KBs抽英寸

它没有缺陷,它工作得很好。在常规

public class Runner{ 


final PipedOutputStream source = new PipedOutputStream(); 
PipedInputStream sink = new PipedInputStream(); 

public static void main(String[] args) { 
    new Runner().doit() 
    println "Finished main thread" 
} 


public void doit() { 

    sink.connect(source) 

    (new Producer(source)).start() 
    BufferedInputStream buffer = new BufferedInputStream(sink) 
    (new Consumer(buffer)).start() 
} 
} 

class Producer extends Thread { 


OutputStream source 
Producer(OutputStream source) { 
    this.source=source 
} 

@Override 
public void run() { 

    byte[] data = new byte[1024]; 

    println "Running the Producer..." 
    FileInputStream fout = new FileInputStream("/Users/ganesh/temp/www/README") 

    int amount=0 
    while((amount=fout.read(data))>0) 
    { 
     String s = new String(data, 0, amount); 
     source.write(s.getBytes()) 
     synchronized (this) { 
      wait(5); 
     } 
    } 

    source.close() 
} 

}

class Consumer extends Thread{ 

InputStream ins 

Consumer(InputStream ins) 
{ 
    this.ins = ins 
} 

public void run() 
{ 
    println "Consumer running" 

    int amount; 
    byte[] data = new byte[1024]; 
    while ((amount = ins.read(data)) >= 0) { 
     String s = new String(data, 0, amount); 
     println "< $s" 
     synchronized (this) { 
      wait(5); 
     } 
    } 

} 

}

+0

sink.close()错过? – zeugor 2017-03-12 23:08:12

-2

--------实施例从我的观点来看是有缺陷。更确切地说,如果在数据流实际写入单个字节之前,应该将数据抽入PipedOutputStream的线程过早死亡,那么存在死锁的高风险。在这种情况下的问题是管道流的实施不能检测到破损的管道。因此,从PipedInputStream读取的线程将永远等待(即死锁)在它的第一次调用read()。

中断管道检测实际上依赖于第一次调用write()作为实现,而不是懒惰地初始化写入端线程,并且只能从那个时间点开始检测破碎管道。

下面的代码重新情况:

import java.io.IOException; 
import java.io.PipedInputStream; 
import java.io.PipedOutputStream; 

import org.junit.Test; 

public class PipeTest 
{ 
    @Test 
    public void test() throws IOException 
    { 
     final PipedOutputStream pout = new PipedOutputStream(); 
     PipedInputStream pin = new PipedInputStream(); 

     pout.connect(pin); 

     Thread t = new Thread(new Runnable() 
     { 
      public void run() 
      { 
       try 
       { 
        if(true) 
        { 
         throw new IOException("asd"); 
        } 
        pout.write(0); // first byte which never get's written 
        pout.close(); 
       } 
       catch(IOException e) 
       { 
        throw new RuntimeException(e); 
       } 
      } 
     }); 
     t.start(); 

     pin.read(); // wait's forever, e.g. deadlocks 
    } 
} 
+0

您希望您的写入和读取操作处于独立线程中。要使消费者不因竞争状态而立即退出,最好在进行读取操作之前执行pin.available()检查以查看它是否大于0。然后你可以重复使用和读取操作,直到可用== 0。在写入器断开的情况下,您还希望对读取端进行异常处理。 – 2015-07-22 22:27:59

+0

当出现异常时,此测试代码无法关闭输出流。如果用'try(OutputStream pout_closed = pout){...}'围绕try块的内容,代码不会死锁。 – 2016-07-12 20:42:28

0

,我与JDK实现看出破绽是:

1)没有超时,读取器或写入可实现无阻碍。

2)当数据被传输超过次优控制(只应与齐平来完成,或者当环形缓冲器已满)

所以我创建了自己解决经由一个ThreadLocal通过上述,(超时值) :

PipedOutputStream

如何使用:

PiedOutputStreamTest

希望它有帮助...