2012-02-28 180 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

希望它有幫助...