2009-12-08 15 views
18

Ich habe zwei Threads. Einer von ihnen schreibt in PipedOutputStream, ein anderer liest aus dem entsprechenden PipedInputStream. Hintergrund ist, dass ein Thread einige Daten vom Remote-Server herunterlädt und sie über Pipestreams zu mehreren anderen Threads multiplext.PipedInputStream - Wie zu vermeiden "java.io.IOException: Rohr gebrochen"

Das Problem ist, dass manchmal (vor allem, wenn das Herunterladen großer (> 50MB) Dateien) Ich java.io.IOException erhalten: Rohr gebrochen, wenn sie von PipedInputStream zu lesen versuchen.
Javadoc sagt, dass 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.
Es ist wahr, mein Schreiben Thread wirklich stirbt nach dem Schreiben aller seiner Daten zu PipedOutputStream.

Irgendwelche Lösungen? Wie kann ich verhindern, dass PipedInputStream diese Ausnahme auslöst? Ich möchte in der Lage sein, alle Daten zu lesen, die in PipedOutputStream geschrieben wurden, selbst wenn der Schreib-Thread seine Arbeit beendet hat. (Wenn jemand weiß, wie man den Thread am Leben hält, bis alle Daten gelesen sind, ist diese Lösung ebenfalls akzeptabel).

Antwort

17

Verwenden Sie java.util.concurrent.CountDownLatch, und beenden Sie nicht den ersten Thread, bevor der zweite Thread signalisiert hat, dass er die Pipeline gelesen hat.

Update: quick and dirty Code mein Kommentar unten

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

Schönes Feature, es ist definitiv +1, aber es muss eine Instanz von CountDownLatch zwischen verschiedenen Threads teilen. Das ist nicht sehr gut, weil das Schreiben und Lesen von Threads an verschiedenen Stellen erzeugt wird und ich möchte, dass sie nicht voneinander wissen. Meine Architektur ist jetzt so, dass sie nur wissen, dass sie in den gegebenen Stream schreiben/lesen sollen. – levanovd

+0

Dann könnten Sie Piped [In | Out] putStream erweitern, um die Manipulation von CountDownLatch zu handhaben. – Jerome

+0

oder schreiben Sie Ihren eigenen Input/OutputStream, der die Pipe und den Latch umschließt (siehe Beispielcode, den ich in meiner Antwort hinzugefügt habe) – Jerome

0

PipedInputStream und PipedOutputStream sind gebrochen zu veranschaulichen (in Bezug auf Threading). Sie gehen davon aus, dass jede Instanz an einen bestimmten Thread gebunden ist. Das ist bizarr. Ich empfehle Ihnen, Ihre eigene (oder zumindest eine andere) Implementierung zu verwenden.

+0

Diese Antwort gibt keinen Wert. In welcher Weise nehmen diese Klassen das an? – matsa

4

Schließen Sie Ihre PipedOutputStream, wenn der Thread, der sie verwendet, endet? Sie müssen dies tun, damit die darin enthaltenen Bytes zu den entsprechenden PipedInputStream gespült werden.

+0

Ja, ich schließe es. – levanovd

+0

Ich denke wirklich, dass hier etwas anderes schief geht, in jedem Fall solltest du niemals ein kaputtes Rohr bekommen, wenn der Schreibfaden normal endete. Wenn ihre Daten nicht in den PipedInputStream passen, sollte sie einfach blockieren, bis Platz ist. – wds

+2

Es ist nicht klar, dass 'close()' 'flush()' impliziert. – Raedwald

Verwandte Themen