簡體   English   中英

PipedInputStream - 如何避免“java.io.IOException:Pipe broken”

[英]PipedInputStream - How to avoid “java.io.IOException: Pipe broken”

我有兩個主題。 其中一個寫入PipedOutputStream,另一個從相應的PipedInputStream讀取。 背景是一個線程正在從遠程服務器下載一些數據,並通過管道流將其多路復用到其他幾個線程。

問題是有時候(特別是在下載大型(> 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的所有數據,即使編寫線程完成了他的工作。 如果有人知道如何繼續寫線程直到所有數據都被讀取,這個解決方案也是可以接受的 )。

使用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);

當你正在使用它的線程結束時,你是否關閉了PipedOutputStream 您需要這樣做,以便將其中的字節刷新到相應的PipedInputStream

PipedInputStreamPipedOutputStream被破壞(關於線程)。 他們假設每個實例都綁定到一個特定的線程。 這很奇怪。 我建議使用您自己的(或至少是不同的)實現。

當您使用多個讀取器或編寫器線程時,您可能會遇到這些類的問題(請參閱JDK-4028322 )。

但是大多數用戶可能只使用一個閱讀器和一個編寫器線程。 既然你也是這種情況,那么你遇到破損管道的原因很可能是你寫完后沒有close PipedOutputStream

PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream(out);

// You can of course also use an Executor or similar for this
new Thread(() -> {
    // Your method writing the data
    writeDataTo(out);
    // Close PipedOutputStream so that reader knows that the end of the data 
    // has been reached
    try {
        out.close();
    }
    catch (IOException e) {
        // Handle exception or simply ignore it; current implementation will NEVER 
        // throw an IOException: https://github.com/openjdk/jdk/blob/0e14d5a98453407488057e6714f90f04d7dfa383/src/java.base/share/classes/java/io/PipedOutputStream.java#L174
    }
}).start();

// Your method reading the data
readDataFrom(in);
// Close PipedInputStream so that writer fails instead of blocking infinitely in case 
// it tries to write again (for whatever reason)
in.close();

也無需手動調用PipedOutputStream.flush() ,它只通知等待的讀者,但如果直接調用close() ,則不會丟失任何數據。

可悲的是,文檔目前還不是很清楚所有這些。 一般來說,依靠實現並不是一個好主意,但在這種情況下,它可能是唯一明智的解決方案:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM