PipeDoutputStream und PipedInputStream
In Java sind PipeDoutputStream und PipeDInputStream Pipeline -Ausgangsströme bzw. Pipeline -Eingangsströme.
Ihre Funktion besteht darin, Multithreads über Pipelines zwischen Threads zu kommunizieren. Bei Verwendung der Pipeline -Kommunikation müssen PipeDoutputStream und PipeDInputStream in Verbindung miteinander verwendet werden.
Bei Verwendung der Pipeline -Kommunikation ist der allgemeine Prozess: Wir schreiben Daten in den PipeDoutputStream in Thread A, und diese Daten werden automatisch an den PipEdInputStream gesendet, der dem PipeDoutputStream entspricht, und dann im Puffer des PipEdInputStream gespeichert wird; Zu diesem Zeitpunkt liest Thread B die Daten im PipEdInputStream. Dies kann die Kommunikation zwischen Thread A und Thread B. erkennen
Im Folgenden betrachten wir das Beispiel der Kommunikation durch Pipelines in Multithreads. Die Beispiele umfassen 3 Klassen: Receiver.java, PipeDStreamtest.java und Sender.java.
Der Code von Receiver.java lautet wie folgt:
importieren java.io.ioException; importieren java.io.pipedInputStream; @SuppressWarnings ("All") / *** Empfänger -Thread* / Public Class Receiver erweitert Thread {// Pipeline -Eingabestream -Objekt. // Es ist an das Objekt "PipeDoutputStream" gebunden, // ermöglicht es Ihnen, die Daten des "PipeDoutputStream" zu empfangen und den Benutzer dann lesen zu lassen. private pipedInputStream in = new pipedInputStream (); // Erhalten Sie das Objekt "Pipe Input Stream" Public PipEDInputStream getInputStream () {return in; } @Override public void run () {ReadMessageonce (); // ReadMessageContinued (); } // Daten einmal aus "Pipe Input Stream" lesen public void ReadMessageonce () {// Obwohl die Größe von BUF 2048 Bytes beträgt, wird es nur höchstens 1024 Bytes aus "Pipe -Eingangsstrom" gelesen. // Weil die Puffergröße des "Pipe -Eingangsstroms" standardmäßig nur 1024 Bytes beträgt. Byte [] buf = neues Byte [2048]; try {int len = in.read (buf); System.out.println (neue String (buf, 0, len)); in.close (); } catch (ioException e) {e.printstacktrace (); }} // Beim Lesen> 1024 Bytes aus "Pipe Input Stream" hören Sie auf, öffentliche void ReadMessageContinued () {int Total = 0; while (true) {byte [] buf = new Byte [1024]; try {int len = in.read (buf); Gesamt += Len; System.out.println (neue String (buf, 0, len)); // Wenn die Gesamtzahl der gelesenen Bytes> 1024 ist, beenden Sie die Schleife. if (insgesamt> 1024) Break; } catch (ioException e) {e.printstacktrace (); }} try {in.close (); } catch (ioException e) {e.printstacktrace (); }}} Der Code von Sender.java lautet wie folgt:
importieren java.io.ioException; importieren java.io.pipedoutputStream; @SuppressWarnings ("All")/ *** Absender Thread*/ Public Class Sender erweitert Thread {// Pipeline Ausgabe -Stream -Objekt. // Es ist an das Objekt "PipeDInputStream" gebunden, // ermöglicht es, dass Daten an die Daten des "PipeDInputStream" gesendet werden, und der Benutzer kann dann die Daten aus dem "PipeDInputStream" lesen. private paceedoutputStream out = new pipeDoutputStream (); // Erhalten Sie das Objekt "Pipe Output Stream". } @Override public void run () {WriteShortMessage (); // WriteLongMessage (); } // Schreiben Sie eine kurze Nachricht in den "Rohrausgangsstrom": "Dies ist eine kurze Nachricht" private void WriteShortMessage () {String strinfo = "Dies ist eine kurze Nachricht"; try {out.write (strinfo.getBytes ()); out.close (); } catch (ioException e) {e.printstacktrace (); }} // Schreiben Sie eine lange Nachricht in den "Pipe Output Stream" private void writeLongMessage () {StringBuilder sb = new StringBuilder (); // 1020 Bytes über eine für die Schleife für (int i = 0; i <102; i ++) sb.append ("0123456789") schreiben; // 26 Bytes mehr schreiben. sb.Append ("abcdefghijklmnopqrstuvwxyz"); // Die Gesamtlänge von STR beträgt 1020+26 = 1046 Bytes String str = sb.toString (); Versuchen Sie {// 1046 Bytes in den "Pipe Output Stream" out.write (str.getBytes ()); out.close (); } catch (ioException e) {e.printstacktrace (); }}} Der Code von PipeDStreamtest.java lautet wie folgt:
Importieren Sie java.io.pipedInputStream; importieren Sie java.io.pipedoutputStream; import Java.io.ioException; @SuppressWarnings ("all") / *** Interaktives Programm für Pipeline -Eingabestream und Pipeline -Ausgabestream* / Public Class PipEdStreamtest {public static void Haupthaupt (String [] Arga -Arg -ARGS) {] {] {] {{{sender t1 = new sender (New Sender () (New Sender (). Empfänger t2 = neuer Empfänger (); PipeDoutputStream out = t1.getOutputStream (); PipedInputStream in = t2.getInputStream (); Versuchen Sie {// Rohranschluss. Die Essenz der folgenden zwei Sätze ist gleich. //out.connect(in); in.connect (out); /** * Startmethode der Thread -Klasse: * Lassen Sie den Thread ausführen; Die Java Virtual Machine ruft die Auslaufmethode des Threads auf. * Das Ergebnis ist, dass zwei Threads gleichzeitig laufen; Der aktuelle Thread (vom Aufruf zur Startmethode zurückgegeben) und der andere Thread (Ausführung seiner Auslaufmethode). * Es ist illegal, einen Thread mehrmals zu starten. Besonders wenn der Thread ausgeführt wurde, kann er nicht neu gestartet werden. */ t1.start (); t2.Start (); } catch (ioException e) {e.printstacktrace (); }}} Auslaufergebnisse:
Dies ist eine kurze Nachricht
veranschaulichen:
(1) in.connect (out); Associates "Pipe Input Stream" und "Pipe Output Stream". Überprüfen Sie den Quellcode von Connect () in PipeDoutputStream.java und PipeDInputStream.java; Wir wissen aus. Connect (in); ist gleichwertig zu in.connect (out);
(2)
t1.start (); // Starten Sie den "Absender" Thread t2.Start (); // Starten Sie den "Empfänger" -Thread
Überprüfen Sie zunächst den Quellcode von Sender.java und führen Sie die Funktion run () aus, nachdem der Thread gestartet wurde. in der run () von sender.java rufen Sie WriteShortMessage () an;
Die Funktion von WriteShortMessage (); ist, Daten "Dies ist eine kurze Nachricht" in den "Rohrausgangsstrom" zu schreiben. Diese Daten werden vom "Pipe -Eingangsstrom" empfangen. Mal sehen, wie dies erreicht wird.
Schauen wir uns zunächst den Quellcode von Write (Byte B []) an und definieren Sie ihn in OutputStream.java. PipeDoutputStream.java erbt von outputStream.java; Der Quellcode von Write (Byte B []) in outputStream.java ist wie folgt:
public void write (byte b []) löst ioException {write (b, 0, B.Length);} aus Tatsächlich ist Write (Byte B []) die Aufruf -Schreibfunktion (Byte B [], int, int len) in PipeDoutputStream.java. Als wir den Quellcode von Write (Byte B [], int Off, int len) betrachteten, stellten wir fest, dass er Sink.Receive (B, Off, Len) nennt; Wenn wir die Definition von Empfang (Byte B [], int Off, int len) betrachten, wissen wir, dass Sink.Receive (B, Off, Len) die Daten im "Rohrausgangsstrom" in den Puffer des "Pipe -Eingangsstroms" speichern soll. Die Standardgröße des Pufferpuffers des "Pipe -Eingangsstroms" beträgt 1024 Bytes.
Zu diesem Zeitpunkt wissen wir, dass: T1.Start () den Absender -Thread startet, und der Absender -Thread schreibt die Daten "Dies ist eine kurze Nachricht" in den "Pipe -Ausgangsstrom". und der "Rohrausgangsstrom" überträgt die Daten in den "Pipe -Eingangsstrom", dh sie wird im Puffer des "Pipe -Eingangsstroms" gespeichert.
Als nächstes betrachten wir "Wie Benutzer Daten aus dem Puffer des 'Pipe Input Stream' lesen". Dies ist tatsächlich die Aktion des Empfänger -Threads.
t2.Start () startet den Empfänger -Thread und führt damit die Funktion von Receiver.java run () aus. Wenn wir uns den Quellcode von Receiver.java ansehen, wissen wir, dass Run () ReadMessageonce () aufruft.
ReadMessageOnce () soll in.Read (BUF) anrufen, um Daten aus dem "Pipe -Eingangsstrom in" zu lesen und sie auf BUF zu speichern.
In der obigen Analyse wissen wir bereits, dass die Daten im Puffer des "Pipe -Eingangsstroms in" "Dies ist eine kurze Nachricht". Daher lautet die Daten von BUF "Dies ist eine Kurznachricht".
Um das Verständnis der Pipeline zu vertiefen. Wir werden die folgenden zwei kleinen Experimente fortsetzen.
Experiment 1: Sender.java ändern
Wille
public void run () {WriteShortMessage (); // WriteLongMessage ();} Modifiziert zu
public void run () {// WriteShortMessage (); WritelongMessage ();} Führen Sie das Programm aus. Das laufende Ergebnis ist:
Diese Daten werden über writeLongMessage () in den "Rohrausgangsstrom" geschrieben und dann in den "Pipe -Eingangsstrom" übertragen und dann im Puffer des "Pipe -Eingangsstroms" gespeichert. und lesen Sie dann vom Benutzer aus dem Puffer vor.
Beobachten Sie dann den Quellcode von WriteLongMessage (). Wir können feststellen, dass die Länge von STR 1046 Bytes beträgt und dann das Ergebnis des Laufens nur 1024 Bytes beträgt! Warum passiert das?
Der Grund ist einfach: Die Standardgröße des Puffers des Pipeline -Eingangsstroms beträgt 1024 Bytes. Daher können höchstens 1024 Bytes geschrieben werden.
Durch die Beobachtung des Quellcodes von PipedInputStream.java können wir gründlicher verstehen.
private statische endgültige int default_pipe_size = 1024; public pipEdInputStream () {initpipe (default_pipe_size);};}; Der Standardkonstruktor ruft initpipe (default_pipe_size) auf, und sein Quellcode lautet wie folgt:
private void initpipe (int pipesize) {if (pipesize <= 0) {werfen Sie neue illegalArgumentException ("Rohrgröße <= 0"); } buffer = new byte [pipesize];} Daraus können wir wissen, dass die Standardgröße des Pufferpuffer 1024 Bytes beträgt.
Experiment 2: Redify Receiver.java auf der Grundlage von "Experiment 1" weiter modifizieren.
Wille
public void run () {ReadMessageonce (); // ReadMessageContinued ();} Modifiziert zu
public void run () {// ReadMessageonce (); ReadMessageContinued ();} Führen Sie das Programm aus. Das laufende Ergebnis ist:
Dieses Ergebnis sind die vollständigen Daten, die in den "Eingabepuffer" geschrieben wurden.
PipedWriter und PipedReader
PipeDWriter ist ein Zeichenpipeline -Ausgangsstrom, der vom Schriftsteller geerbt wird.
PipedReader ist ein Charakter -Pipeline -Eingabestream, der vom Schriftsteller erbt.
Die Funktion des Rohrleiters und des PipeDreaders besteht darin, zwischen den Gewäfen durch Pipelines zu kommunizieren. Bei Verwendung der Pipeline -Kommunikation müssen PipedWriter und PipeDreader in Verbindung miteinander verwendet werden.
Im Folgenden betrachten wir Beispiele für Kommunikation über PipedWriter und PipedReader in Multithreading. Die Beispiele umfassen 3 Klassen: Receiver.java, Sender.java und Pipetest.java
Der Code von Receiver.java lautet wie folgt:
importieren java.io.ioException; importieren java.io.pipedreader; @SuppressWarnings ("All") / *** Empfänger -Thread* / Public Class Receiver erweitert Thread {// Pipeline -Eingabestream -Objekt. // Es ist an das "PipedWriter" -Objekt gebunden, // Ermöglicht es Ihnen, die Daten des "PipedWriter" zu empfangen und dann den Benutzer zu lesen. private pipedReader in = new pipedReader (); // "Pipe Input Stream Object" abrufen public pipedReader getReader () {return in; } @Override public void run () {ReadMessageonce (); // ReadMessageContinued (); } // Daten einmal aus "Pipe Input Stream" Lesen Sie public void ReadMessageonce () {// Obwohl die Größe von BUF 2048 Zeichen beträgt, wird es nur höchstens 1024 Zeichen aus "Pipe -Eingangsstrom" gelesen. // Da die Puffergröße des "Pipe -Eingangsstroms" standardmäßig nur 1024 Zeichen beträgt. char [] buf = new char [2048]; try {int len = in.read (buf); System.out.println (neue String (buf, 0, len)); in.close (); } catch (ioException e) {e.printstacktrace (); }} // Beim Lesen> 1024 Zeichen aus "Pipe Input Stream" hören Sie auf, die öffentliche void ReadMessageContinued () {int Total = 0; while (true) {char [] buf = new char [1024]; try {int len = in.read (buf); Gesamt += Len; System.out.println (neue String (buf, 0, len)); // Wenn die Gesamtzahl der gelesenen Zeichen> 1024 ist, wird die Schleife beendet. if (insgesamt> 1024) Break; } catch (ioException e) {e.printstacktrace (); }} try {in.close (); } catch (ioException e) {e.printstacktrace (); }}} Der Code von Sender.java lautet wie folgt:
importieren java.io.ioException; import Java.io.pipedWriter; @SuppressWarnings ("All")/ *** Absender Thread*/ Public Class Sender erweitert Thread {// Pipeline Ausgabe -Stream -Objekt. // Es ist an das "PipeDreader" -Objekt gebunden, // Ermöglicht es, dass Daten an die Daten des "PipeDreaders" gesendet werden und der Benutzer die Daten dann aus dem "PipeDreader" lesen kann. privatem PipedWriter out = neuer Rohrleiter (); // Holen Sie sich das Objekt "Pipe Output Stream" öffentlicher Rohrleiter getWriter () {return out; } @Override public void run () {WriteShortMessage (); // WriteLongMessage (); } // Schreiben Sie eine kurze Nachricht in den "Rohrausgangsstrom": "Dies ist eine kurze Nachricht" private void WriteShortMessage () {String strinfo = "Dies ist eine kurze Nachricht"; try {out.write (strinfo.toarArray ()); out.close (); } catch (ioException e) {e.printstacktrace (); }} // Schreiben Sie eine lange Nachricht in den "Pipe Output Stream" private void writeLongMessage () {StringBuilder sb = new StringBuilder (); // 1020 Zeichen über eine für Schleife schreiben für (int i = 0; i <102; i ++) sb.append ("0123456789"); // 26 Zeichen mehr schreiben. sb.Append ("abcdefghijklmnopqrstuvwxyz"); // Die Gesamtlänge von STR beträgt 1020+26 = 1046 Zeichen String str = sb.toString (); Versuchen Sie {// 1046 Zeichen in den "Rohrausgangsstrom" out.write (str); out.close (); } catch (ioException e) {e.printstacktrace (); }}} Der Code von pipetest.java lautet wie folgt:
Importieren Sie java.io.pipedreader; import java.io.pipedwriter; import Java.io.ioException; @Suppresswarnings ("All") / *** Interaktives Programm für Pipeline -Eingänge Stream und Pipeline Ausgabe Stream* / public class pipetest {public static void Main (String [] args) {{sender t1 = new Sendeer (). Empfänger t2 = neuer Empfänger (); PoceedWriter out = t1.getWriter (); PIPEDREADER IN = T2.GetReader (); Versuchen Sie {// Rohranschluss. Die Essenz der folgenden zwei Sätze ist gleich. //out.connect(in); in.connect (out); /** * Startmethode der Thread -Klasse: * Lassen Sie den Thread ausführen; Die Java Virtual Machine ruft die Auslaufmethode des Threads auf. * Das Ergebnis ist, dass zwei Threads gleichzeitig laufen; Der aktuelle Thread (vom Aufruf zur Startmethode zurückgegeben) und der andere Thread (Ausführung seiner Auslaufmethode). * Es ist illegal, einen Thread mehrmals zu starten. Besonders wenn der Thread ausgeführt wurde, kann er nicht neu gestartet werden. */ t1.start (); t2.Start (); } catch (ioException e) {e.printstacktrace (); }}} Auslaufergebnisse:
Dies ist eine kurze Nachricht
Ergebnisse Beschreibung:
(1)
in.connect (out);
Seine Funktion besteht darin, den "Pipe -Eingangsstrom" und den "Rohrausgangsstrom" zu verknüpfen. Überprüfen Sie den Quellcode von Connect () in PipedWriter.java und PipeDreader.java; Wir wissen aus. Connect (in); ist gleichwertig zu in.connect (out);
(2)
t1.start (); // Starten Sie den "Absender" Thread t2.Start (); // Starten Sie den "Empfänger" -Thread
Überprüfen Sie zunächst den Quellcode von Sender.java und führen Sie die Funktion run () aus, nachdem der Thread gestartet wurde. in der run () von sender.java rufen Sie WriteShortMessage () an;
Die Funktion von WriteShortMessage (); ist, Daten "Dies ist eine kurze Nachricht" in den "Rohrausgangsstrom" zu schreiben. Diese Daten werden vom "Pipe -Eingangsstrom" empfangen. Mal sehen, wie dies erreicht wird.
Schauen wir uns zunächst den Quellcode von Write (char char. PipedWriter.java erbt von writer
public void write (char cbuf []) löst IOException {write (cbuf, 0, cbuf.length);} aus;}
Tatsächlich ist Write (char c []) die Funktion "Call write" (char c [], int off, int len) in pipedWriter.java. Als wir den Quellcode von Write (char c [], int, int len) betrachteten, stellten wir fest, dass er Sink.Receive (CBUF, Off, Len) nennt; Wenn wir die Definition von Empfang (char c [], int, int len) weiter betrachten, wissen wir, dass Sink.Receive (CBUF, Off, Len) die Daten im "Rohrausgangsstrom" in den Puffer des "Pipe -Eingangsstroms" speichern soll. Die Standardgröße des Pufferpuffers des "Pipe -Eingangsstroms" beträgt 1024 Zeichen.
Zu diesem Zeitpunkt wissen wir, dass: T1.Start () den Absender -Thread startet, und der Absender -Thread schreibt die Daten "Dies ist eine kurze Nachricht" in den "Pipe -Ausgangsstrom". und der "Rohrausgangsstrom" überträgt die Daten in den "Pipe -Eingangsstrom", dh sie wird im Puffer des "Pipe -Eingangsstroms" gespeichert.
Als nächstes betrachten wir "Wie Benutzer Daten aus dem Puffer des 'Pipe Input Stream' lesen". Dies ist tatsächlich die Aktion des Empfänger -Threads.
t2.Start () startet den Empfänger -Thread und führt damit die Funktion von Receiver.java run () aus. Wenn wir uns den Quellcode von Receiver.java ansehen, wissen wir, dass Run () ReadMessageonce () aufruft.
ReadMessageOnce () soll in.Read (BUF) anrufen, um Daten aus dem "Pipe -Eingangsstrom in" zu lesen und sie auf BUF zu speichern.
In der obigen Analyse wissen wir bereits, dass die Daten im Puffer des "Pipe -Eingangsstroms in" "Dies ist eine kurze Nachricht". Daher lautet die Daten von BUF "Dies ist eine Kurznachricht".
Um das Verständnis der Pipeline zu vertiefen. Wir werden die folgenden zwei kleinen Experimente fortsetzen.
Experiment 1: Sender.java ändern
Wille
public void run () {WriteShortMessage (); // WriteLongMessage ();} Modifiziert zu
public void run () {// WriteShortMessage (); WritelongMessage ();} Führen Sie das Programm aus. Die Betriebsergebnisse sind wie folgt:
Daraus können wir sehen, dass das Programm falsch läuft! Ausnahme werfen java.io.ioException: Pipe geschlossen
Warum passiert das?
Ich werde den Programmfluss analysieren.
(1) in Pipetest die Eingangs- und Ausgangspipelines durch IN.Connect (OUT) anschließen; Dann starten Sie zwei Threads. t1.start () startet den Thread -Absender und t2.Start () startet den Thread -Empfänger.
(2) Nach dem Start des Absendungs -Threads werden die Daten über writeLongMessage () und out.write (str. tocharArray ()) in die "Ausgabemittel -Pipeline" geschrieben, die insgesamt 1046 Zeichen schreibt. Gemäß dem Quellcode von PipedWriter wird die Funktion write () des Rohrwriters die Receise () -Funktion von PipeDreader aufrufen. Angesichts der Receme () -Funktion von PipedReader wissen wir, dass PipeDreader den akzeptierten Datenpuffer speichert. Wenn Sie die Funktion empfangen () sorgfältig beobachten, gibt es den folgenden Code:
while (in == out) {if ((readside! = null) &&! } / * voll: Kick alle wartenden Leser * / notifyAll (); versuche {warte (1000); } catch (interruptedException ex) {throw New java.io.interruptedioException (); }} Die anfänglichen Werte von In und OUT sind in = -1, out = 0; kombiniert mit der oben genannten Zeit (in == out). Wir wissen, dass es bedeutet, dass jedes Mal, wenn ein Charakter in die Pipeline geschrieben wird, die Bedingung in == Out erfüllt ist. Dann ist notifyAll () aufgerufen, um den "Thread, der die Pipeline liest" aufzuwecken.
Das heißt, jedes Mal, wenn ein Charakter in die Pipeline geschrieben wird, blockiert er und wartet auf das Lesen anderer Themen.
Die Standardgröße des PipedReader -Puffers beträgt jedoch 1024! Zu diesem Zeitpunkt müssen jedoch 1046 Daten geschrieben werden! Daher können höchstens 1024 Zeichen gleichzeitig geschrieben werden.
(03) Nach dem Start des Empfänger -Threads wird ReadMessageonce () aufgerufen, um den Pipeline -Eingangsstrom zu lesen. Das Lesen von 1024 Zeichen wird durchgeführt, und Close () wird zum Schließen gerufen.
Aus der Analyse von (02) und (03) ist ersichtlich, dass der Absender 1046 Zeichen in die Pipeline schreiben muss. Unter ihnen können die ersten 1024 Zeichen (die Pufferkapazität 1024) normal geschrieben werden, und eine wird für jedes Schreiben gelesen. Wenn 1025 Zeichen geschrieben werden, schreiben Sie () in PipeDWriter.java immer noch nacheinander. Dann wird empfangen () in PipeDreader.java genannt; In PipedReader.java wird die Empfangsfunktion (int c) schließlich aufgerufen. Zu diesem Zeitpunkt wurde der Pipeline -Eingangsstrom geschlossen, dh Conted Byreader ist wahr, also werfen Sie neue IOException ("Pipe Closed") geworfen.
Wir ändern weiterhin "Test One", um das Problem zu lösen.
Experiment 2: Weitere modifizieren Sie den Receiver.java auf der Grundlage von "Experiment 1".
public void run () {ReadMessageonce (); // ReadMessageContinued ();} Modifiziert zu
public void run () {// ReadMessageonce (); ReadMessageContinued ();} Zu diesem Zeitpunkt kann das Programm normal ausgeführt. Das laufende Ergebnis ist: