2009-12-08 102 views
18

我有两个线程。其中一个写入PipedOutputStream,另一个从相应的PipedInputStream读取。背景是,一个线程正在从远程服务器下载一些数据,并通过管道流将其多路复用到其他几个线程。PipedInputStream - 如何避免“java.io.IOException:管道损坏”

的问题是,有时(特别是下载大(> 50MB的时候)文件)我得到产生java.io.IOException:管道试图从的PipedInputStream读取时坏
Javadoc说A pipe is said to be broken if a thread that was providing data bytes to the connected piped output stream is no longer alive.
确实,我的写作线程在将所有数据写入PipedOutputStream后真的死亡。

任何解决方案?我怎样才能防止PipedInputStream抛出这个异常?即使写作线程完成了他的工作,我也希望能够读取写入PipedOutputStream的所有数据。 (如果有人知道如何继续写入线程直到读取所有数据,这个解决方案也可以接受)。

回答

17

使用java.util.concurrent.CountDownLatch,并且不会在第二个线程发出信号并且已经完成从管道读取之前结束第一个线程。

更新:快速和肮脏的代码来说明我的评论下面

final PipedInputStream pin = getInputStream(); 
    final PipedOutputStream pout = getOutputStream(); 

    final CountDownLatch latch = new CountDownLatch(1); 

    InputStream in = new InputStream() { 

     @Override 
     public int read() throws IOException { 
      return pin.read(); 
     } 

     @Override 
     public void close() throws IOException { 
      super.close(); 
      latch.countDown(); 
     } 
    }; 


    OutputStream out = new OutputStream(){ 

     @Override 
     public void write(int b) throws IOException { 
      pout.write(b); 
     } 

     @Override 
     public void close() throws IOException { 
      while(latch.getCount()!=0) { 
       try { 
        latch.await(); 
       } catch (InterruptedException e) { 
        //too bad 
       } 
      } 
      super.close(); 
     } 
    }; 

    //give the streams to your threads, they don't know a latch ever existed 
    threadOne.feed(in); 
    threadTwo.feed(out); 
+0

不错的功能,它肯定是+1,但它需要在不同线程之间共享一个CountDownLatch实例。这不太好,因为写作和阅读主题是在不同的地方创建的,我希望他们不要彼此了解。我现在的架构是这样的,他们只知道应该写入/读取给定流中的数据。 – levanovd 2009-12-08 11:48:05

+0

然后,可能会扩展Piped [In | Out] putStream来处理CountDownLatch的操作。 – Jerome 2009-12-08 11:53:04

+0

或编写自己的包装管道和锁存器的Input/OutputStream(请参阅我在答案中添加的示例代码) – Jerome 2009-12-08 14:33:22

0

PipedInputStreamPipedOutputStream被破坏(关于线程)。他们假设每个实例都绑定到一个特定的线程。这是奇怪的。我建议使用你自己的(或者至少不同的)实现。

+0

此响应不提供任何价值。这些课程以什么方式假设这一点? – matsa 2017-11-29 13:40:51

4

当你正在使用它的线程结束时,你正在关闭你的PipedOutputStream吗?您需要这样做,以便将其中的字节刷新到相应的PipedInputStream

+0

是的,我关闭它。 – levanovd 2009-12-08 14:19:17

+0

我真的觉得别的东西在这里出了问题,在任何情况下,如果写入线程正常结束,你永远不会收到损坏的管道。如果它的数据不适合'PipedInputStream',它应该阻塞直到有空间。 – wds 2009-12-08 16:32:43

+2

不清楚'close()'意味着'flush()'。 – Raedwald 2012-02-28 13:59:58

相关问题