PipeDoutputStream y PipeDInputStream
En Java, PipeDoutputStream y PipeDInputStream son flujos de salida de tuberías y flujos de entrada de tuberías, respectivamente.
Su función es permitir que los múltiples lecturas se comuniquen entre hilos a través de tuberías. Al usar la comunicación de tuberías, PipeDoutputStream y PipeDInputStream deben usarse junto entre sí.
Al usar la comunicación de la tubería, el proceso general es: escribimos datos al PipeDoutputStream en el subproceso A, y estos datos se enviarán automáticamente al PipeDInputStream correspondiente al PipeDoutputStream, y luego se almacenan en el búfer de PipeDInputStream; En este momento, Thread B lee los datos en PipeDInputStream. Esto puede realizar la comunicación entre el hilo A y el hilo B.
A continuación, observamos el ejemplo de comunicación a través de tuberías en múltiples lecturas. Los ejemplos incluyen 3 clases: receptor.java, pipedstreamtest.java y stader.java.
El código de receptor.java es el siguiente:
import java.io.ioException; import java.io.pipedinputstream; @SupplesSWarnings ("All") / *** RECEPTER PRESO* / Public Class receptor extiende el hilo {// objeto de flujo de entrada de tubería. // Está vinculado al objeto "PipeDoutputStream", // Esto le permite recibir los datos del "PipeDoutputStream" y luego dejar que el usuario lo lea. PipeDInputStream privado en = new PipeDInputStream (); // Obtenga el objeto "Flojo de entrada de tuberías" Public PipeDInputStream getInputStream () {return in; } @Override public void run () {readMessageOnce (); // ReadMessageContinued (); } // Leer datos una vez del "flujo de entrada de tubería" public void ReadMessageonce () {// Aunque el tamaño de BUF es de 2048 bytes, solo se lee como máximo 1024 bytes de "Pipe Input Stream". // porque el tamaño del búfer de la "secuencia de entrada de tubería" es solo 1024 bytes de forma predeterminada. byte [] buf = nuevo byte [2048]; intente {int len = in.read (buf); System.out.println (nueva cadena (buf, 0, len)); cercar(); } catch (ioException e) {E.PrintStackTrace (); }} // Al leer> 1024 bytes del "flujo de entrada de tubería", deje de leer public void readMessageContinUed () {int total = 0; while (true) {byte [] buf = new Byte [1024]; intente {int len = in.read (buf); total += len; System.out.println (nueva cadena (buf, 0, len)); // Si el número total de bytes se lee es> 1024, salga del bucle. if (total> 1024) ruptura; } catch (ioException e) {E.PrintStackTrace (); }} try {in.close (); } catch (ioException e) {E.PrintStackTrace (); }}} El código de Sender.java es el siguiente:
import java.io.ioException; import java.io.pipeDoutputStream; @SupplesSWarnings ("All")/ *** Servidor de subproceso*/ Public Class El remitente extiende el hilo {// Objeto de transmisión de salida de la tubería. // Está vinculado al objeto "PipeDInputStream", // Esto permite que los datos se envíen a los datos del "PipeDInputStream", y el usuario puede leer los datos del "PipeDInputStream". privado PipeDoutputStream out = new PipeDoutputStream (); // Obtenga el objeto "Storn de salida de tuberías" Public PipeDoutputStream GetOutputStream () {return out; } @Override public void run () {writeShortMessage (); // WriteLongMessage (); } // Escribe un mensaje breve en el "flujo de salida de tubería": "Este es un mensaje corto" privado void writeShortMessage () {String strinfo = "Este es un mensaje corto"; intente {out.write (strinfo.getBytes ()); out.close (); } catch (ioException e) {E.PrintStackTrace (); }} // Escribe un mensaje largo en el "flujo de salida de tubería" privado writeLongMessage () {StringBuilder sb = new StringBuilder (); // Escribe 1020 bytes a través de un bucle for (int i = 0; i <102; i ++) sb.append ("0123456789"); // Escribe 26 bytes más. sb.append ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); // La longitud total de STR es 1020+26 = 1046 bytes String Str = Sb.ToString (); Pruebe {// escriba 1046 bytes en la "transmisión de salida de tubería" out.write (str.getBytes ()); out.close (); } catch (ioException e) {E.PrintStackTrace (); }}} El código de PipedStreamTest.java es el siguiente:
import java.io.pipedinputStream; import java.io.pipeDoutputStream; import java.io.ioException; @SupessWarnings ("All") / *** Programa interactivo para la transmisión de entrada de tuberías y la transmisión de salida de tuberías* / Clase pública PipedStreamTeamTeamTeamTest {public estatic estatic bain (] args) {sendero t1 = nuevo sendero sendero () Receptor T2 = nuevo receptor (); PipeDoutputStream out = t1.getOutputStream (); PipeDInputStream in = t2.getInputStream (); Pruebe {// Conexión de tubería. La esencia de las siguientes dos oraciones es la misma. //out.connect(in); in.connect (out); /** * Método de inicio de la clase de subprocesos: * Haga que el hilo comience a ejecutar; La máquina virtual Java llama al método de ejecución del hilo. * El resultado es que dos hilos funcionan simultáneamente; El subproceso actual (devuelto desde la llamada al método de inicio) y el otro hilo (ejecutando su método de ejecución). * Es ilegal comenzar un hilo varias veces. Especialmente cuando el hilo ha terminado de ejecutarse, no se puede reiniciar. */ t1.start (); t2.start (); } catch (ioException e) {E.PrintStackTrace (); }}} Resultados de ejecución:
Este es un mensaje corto
ilustrar:
(1) in.connect (fuera); Asociados "Corriente de entrada de tubería" y "flujo de salida de tubería". Verifique el código fuente de Connect () en PipeDoutputStream.java y PipeDInputStream.java; sabemos out.connect (in); es equivalente a in.connect (out);
(2)
t1.start (); // Inicie el hilo "remitente" t2.start (); // Inicie el hilo de "receptor"
Primero verifique el código fuente de Sender.java y ejecute la función Run () después de que se inicia el hilo; En la ejecución () de Sender.java, llame a WriteShortMessage ();
La función de WriteShortMessage (); es escribir datos "Este es un mensaje breve" en el "flujo de salida de tubería"; Estos datos serán recibidos por el "flujo de entrada de tubería". Veamos cómo se logra esto.
Primero veamos el código fuente de escritura (byte b []) y lo definamos en outputStream.java. PipeDoutputStream.java hereda de OutputStream.java; El código fuente de escritura (byte b []) en outputStream.java es el siguiente:
Public void Write (byte b []) lanza ioexception {Write (b, 0, b.length);} De hecho, escribir (byte b []) es la función de escritura de llamada (byte b [], int off, int len) en pipeDoutputStream.java. Mirando el código fuente de escritura (byte b [], int off, int Len), encontramos que llamará a sink.receive (b, off, len); Mirando aún más la definición de recibir (byte b [], int off, int len), sabemos que sink.Receive (b, off, len) es guardar los datos en la "corriente de salida de la tubería" en el búfer de la "corriente de entrada de la tubería". El tamaño predeterminado del búfer de búfer de la "corriente de entrada de tubería" es de 1024 bytes.
En este punto, sabemos que: t1.start () inicia el hilo del remitente, y el hilo del remitente escribirá los datos "Este es un mensaje corto" en el "flujo de salida de tubería"; y el "flujo de salida de la tubería" transferirá los datos al "flujo de entrada de tubería", es decir, se guardará en el búfer de la "corriente de entrada de la tubería".
A continuación, observamos "cómo los usuarios leen datos del búfer del 'flujo de entrada de tubería'". Esta es en realidad la acción del hilo del receptor.
t2.start () iniciará el hilo del receptor, ejecutando así la función receptor.java run (). Mirando el código fuente de receptor.java, sabemos que Run () llama a ReadMessageUnce ().
ReadMessageOnce () es llamar a la lectura (BUF) para leer los datos del "flujo de entrada de tubería" y guardarlos en BUF.
A través del análisis anterior, ya sabemos que los datos en el búfer de la "corriente de entrada de tubería en" es "Este es un mensaje corto"; Por lo tanto, los datos de BUF son "Este es un mensaje corto".
Para profundizar la comprensión de la tubería. Continuaremos los siguientes dos pequeños experimentos.
Experimento 1: modificar remitente.java
Voluntad
public void run () {WriteShortMessage (); // writeLongMessage ();} Modificado a
public void run () {// writeShortMessage (); WriteLongMessage ();} Ejecutar el programa. El resultado de la ejecución es:
Estos datos se escriben en la "corriente de salida de la tubería" a través de WriteLongMessage (), y luego se transfieren a la "corriente de entrada de tubería", y luego se almacenan en el búfer de la "corriente de entrada de la tubería"; y luego lea del búfer por el usuario.
Luego, observe el código fuente de WriteLongMessage (). Podemos encontrar que la longitud de STR es 1046 bytes, ¡y luego el resultado de correr es solo 1024 bytes! ¿Por qué está sucediendo esto?
La razón es simple: el tamaño predeterminado del búfer de la secuencia de entrada de la tubería es de 1024 bytes. Por lo tanto, como máximo, se pueden escribir 1024 bytes.
Al observar el código fuente de PipeDInputStream.java, podemos entender más a fondo.
Private static final int default_pipe_size = 1024; public pipeDinputStream () {initPipe (default_pipe_size);} El constructor predeterminado llama a initPipe (default_pipe_size), y su código fuente es el siguiente:
Private void initPipe (int pipeSize) {if (pipeSize <= 0) {tire nueva ilegalArgumentException ("tamaño de tubería <= 0"); } buffer = new Byte [pipeSize];} A partir de esto, podemos saber que el tamaño predeterminado del búfer del búfer es de 1024 bytes.
Experimento 2: Continúe modificando el receptor.java sobre la base del "Experimento 1"
Voluntad
public void run () {readMessageOnce (); // readMessageContinued ();} Modificado a
public void run () {// readMessageOnce (); readMessageContinued ();} Ejecutar el programa. El resultado de la ejecución es:
Este resultado son los datos completos escritos en el "búfer de entrada".
Pipeedwriter y PipeDreader
PipeDwriter es una secuencia de salida de tuberías de personajes, que se hereda del escritor.
PipeDreader es un flujo de entrada de tuberías de personajes que hereda del escritor.
La función de PipeDwriter y PipeDreader es comunicarse entre hilos a través de tuberías. Cuando se usa la comunicación de tuberías, PipeDwriter y PipeedReader deben usarse junto entre sí.
A continuación, observamos ejemplos de comunicación a través de PipeDwriter y PipeedReader en Multhrithreading. Los ejemplos incluyen 3 clases: receptor.java, sender.java y pipetest.java
El código de receptor.java es el siguiente:
import java.io.ioException; import java.io.pipedreader; @SupplesSWarnings ("All") / *** RECEPTER PRESO* / Public Class receptor extiende el hilo {// objeto de flujo de entrada de tubería. // Está vinculado al objeto "PipeDwriter", // Esto le permite recibir los datos del "PipeedWriter" y luego dejar que el usuario lo lea. PipeedReader privado en = new PipeDReader (); // Obtener el "objeto de flujo de entrada de tubería" PipeedReader público getReader () {return in; } @Override public void run () {readMessageOnce (); // ReadMessageContinued (); } // Lea los datos una vez del "flujo de entrada de tubería" public void readMessageonce () {// Aunque el tamaño de BUF es de 2048 caracteres, solo se leerá como máximo 1024 caracteres de "Pipe Input Stream". // porque el tamaño del búfer de la "secuencia de entrada de tubería" es de solo 1024 caracteres de forma predeterminada. char [] buf = nuevo char [2048]; intente {int len = in.read (buf); System.out.println (nueva cadena (buf, 0, len)); cercar(); } catch (ioException e) {E.PrintStackTrace (); }} // Al leer> 1024 caracteres de "Pipe Input Stream", deja de leer public void ReadMessageContinUed () {int Total = 0; while (true) {char [] buf = new Char [1024]; intente {int len = in.read (buf); total += len; System.out.println (nueva cadena (buf, 0, len)); // Si el número total de caracteres se lee es> 1024, se sale el bucle. if (total> 1024) ruptura; } catch (ioException e) {E.PrintStackTrace (); }} try {in.close (); } catch (ioException e) {E.PrintStackTrace (); }}} El código de Sender.java es el siguiente:
import java.io.ioException; import java.io.pipedwriter; @SupplesSWarnings ("All")/ *** Servidor de subproceso*/ Public Class El remitente extiende el hilo {// Objeto de transmisión de salida de la tubería. // Está vinculado al objeto "PipeedReader", // Esto permite que los datos se envíen a los datos del "PipeedReader" y el usuario puede leer los datos del "PipeedReader". PipeDwriter privado out = new PipeDwriter (); // Obtenga el objeto "Storn de salida de tubería" Public PipeDwriter getWriter () {return out; } @Override public void run () {writeShortMessage (); // WriteLongMessage (); } // Escribe un mensaje breve en el "flujo de salida de tubería": "Este es un mensaje corto" privado void writeShortMessage () {String strinfo = "Este es un mensaje corto"; prueba {out.write (strinfo.toCarArray ()); out.close (); } catch (ioException e) {E.PrintStackTrace (); }} // Escribe un mensaje largo en el "flujo de salida de tubería" privado writeLongMessage () {StringBuilder sb = new StringBuilder (); // Escribe 1020 caracteres a través de un bucle for (int i = 0; i <102; i ++) sb.append ("0123456789"); // Escribe 26 caracteres más. sb.append ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); // La longitud total de STR es 1020+26 = 1046 caracteres String Str = Sb.ToString (); intente {// escriba 1046 caracteres en la "transmisión de salida de tubería" out.write (str); out.close (); } catch (ioException e) {E.PrintStackTrace (); }}} El código de pipetest.java es el siguiente:
import java.io.pipedreader; import java.io.pipedwriter; import java.io.ioexception; @SupessWarnings ("all") / *** Programa interactivo para la transmisión de entrada de tuberías y la transmisión de salida de la tubería* / public class PipeTest {public static void Main (String [] args) {sendero T1 = nuevo enviador (); Receptor T2 = nuevo receptor (); PipeDwriter out = t1.getwriter (); PipeDReader en = t2.getReader (); Pruebe {// Conexión de tubería. La esencia de las siguientes dos oraciones es la misma. //out.connect(in); in.connect (out); /** * Método de inicio de la clase de subprocesos: * Haga que el hilo comience a ejecutar; La máquina virtual Java llama al método de ejecución del hilo. * El resultado es que dos hilos funcionan simultáneamente; El subproceso actual (devuelto desde la llamada al método de inicio) y el otro hilo (ejecutando su método de ejecución). * Es ilegal comenzar un hilo varias veces. Especialmente cuando el hilo ha terminado de ejecutarse, no se puede reiniciar. */ t1.start (); t2.start (); } catch (ioException e) {E.PrintStackTrace (); }}} Resultados de ejecución:
Este es un mensaje corto
Descripción de los resultados:
(1)
in.connect (out);
Su función es asociar la "corriente de entrada de la tubería" y la "corriente de salida de la tubería". Verifique el código fuente de Connect () en PipeDwriter.java y PipeDreader.java; sabemos out.connect (in); es equivalente a in.connect (out);
(2)
t1.start (); // Inicie el hilo "remitente" t2.start (); // Inicie el hilo de "receptor"
Primero verifique el código fuente de Sender.java y ejecute la función Run () después de que se inicia el hilo; En la ejecución () de Sender.java, llame a WriteShortMessage ();
La función de WriteShortMessage (); es escribir datos "Este es un mensaje breve" en el "flujo de salida de tubería"; Estos datos serán recibidos por el "flujo de entrada de tubería". Veamos cómo se logra esto.
Primero veamos el código fuente de escritura (char Char. Pipedwriter.java herede de Writer.java; El código fuente de escritura (char c []) en escritor.java es el siguiente:
Public void Write (char cbuf []) lanza ioexception {Write (Cbuf, 0, cbuf.length);}
De hecho, escribir (char c []) es la función de escritura de llamada (char c [], int off, int len) en pipedwriter.java. Mirando el código fuente de escritura (char c [], int off, int Len), descubrimos que llamará a sink.Receive (cbuf, off, len); Mirando aún más la definición de recibir (char c [], int off, int Len), sabemos que sink.Receive (CBUF, OFF, LEN) es guardar los datos en la "corriente de salida de la tubería" en el búfer de la "corriente de entrada de la tubería". El tamaño predeterminado del búfer de búfer de "flujo de entrada de tubería" es de 1024 caracteres.
En este punto, sabemos que: t1.start () inicia el hilo del remitente, y el hilo del remitente escribirá los datos "Este es un mensaje corto" en el "flujo de salida de tubería"; y el "flujo de salida de la tubería" transferirá los datos al "flujo de entrada de tubería", es decir, se guardará en el búfer de la "corriente de entrada de la tubería".
A continuación, observamos "cómo los usuarios leen datos del búfer del 'flujo de entrada de tubería'". Esta es en realidad la acción del hilo del receptor.
t2.start () iniciará el hilo del receptor, ejecutando así la función receptor.java run (). Mirando el código fuente de receptor.java, sabemos que Run () llama a ReadMessageUnce ().
ReadMessageOnce () es llamar a la lectura (BUF) para leer los datos del "flujo de entrada de tubería" y guardarlos en BUF.
A través del análisis anterior, ya sabemos que los datos en el búfer de la "corriente de entrada de tubería en" es "Este es un mensaje corto"; Por lo tanto, los datos de BUF son "Este es un mensaje corto".
Para profundizar la comprensión de la tubería. Continuaremos los siguientes dos pequeños experimentos.
Experimento 1: modificar remitente.java
Voluntad
public void run () {WriteShortMessage (); // writeLongMessage ();} Modificado a
public void run () {// writeShortMessage (); WriteLongMessage ();} Ejecutar el programa. Los resultados de la operación son los siguientes:
¡A partir de esto, podemos ver que el programa se ejecuta incorrectamente! Lanzar excepción java.io.ioException: tubería cerrada
¿Por qué está sucediendo esto?
Analizaré el flujo del programa.
(1) En Pipetest, conecte las tuberías de entrada y salida a través de IN.Connect (Out); Luego, comience dos hilos. t1.start () inicia el remitente de subprocesos y t2.start () inicia el receptor de subprocesos.
(2) Después de que se inicia el hilo del remitente, los datos se escriben en la "tubería de salida" a través de WriteLongMessage (), y Out.Write (str.toCarArray ()) escribe un total de 1046 caracteres. De acuerdo con el código fuente de PipeDwriter, la función Write () de PipeDwriter llamará a la función Recibe () de PipeedReader. Mirando la función Recibir () de PipeDreader, sabemos que PipeDreader almacenará el búfer de datos aceptado. Si observa la función Recibe () con cuidado, existe el siguiente código:
while (in == out) {if ((readside! = null) &&! readside.isalive ()) {tire nueva ioexception ("tubería rota"); } / * completo: patear a cualquier lectores que esperen * / notifyall (); intente {espera (1000); } catch (InterruptedException ex) {tire nuevo java.io.interruptedioException (); }} Los valores iniciales de In y Out son in = -1, Out = 0, respectivamente; combinado con lo anterior while (in == out). Sabemos que su significado es que cada vez que un personaje se escribe en la tubería, se cumple la condición in ==. Entonces, NotifyAll () está llamado a despertar el "hilo que lee la tubería".
Es decir, cada vez que un personaje se escribe en la tubería, bloqueará y esperará a que se lean otros hilos.
Sin embargo, ¡el tamaño predeterminado del búfer de PipeedReader es 1024! Sin embargo, ¡hay 1046 datos por escribir en este momento! Por lo tanto, como máximo, se pueden escribir 1024 caracteres a la vez.
(03) Después de que se inicia el hilo del receptor, se llamará a ReadMessageUnce () para leer el flujo de entrada de la tubería. Se realizarán 1024 caracteres, y Close () se llamará para cerrar, tubería.
A partir del análisis de (02) y (03), se puede ver que el remitente necesita escribir 1046 caracteres en la tubería. Entre ellos, los primeros 1024 caracteres (la capacidad del búfer es 1024) se pueden escribir normalmente, y uno se lee para cada escritura. Cuando se escriben 1025 caracteres, Write () en PipeDwriter.java todavía se llama en secuencia; Luego, recibe () en PipeDreader.java se llama; En PipedReader.java, eventualmente se llamará a la función Recibir (int c). En este momento, se ha cerrado la corriente de entrada de la tubería, es decir, el cerrado es cierto, por lo que se lanza una nueva IOException ("tubería cerrada").
Continuamos modificando la "prueba uno" para resolver el problema.
Experimento 2: Continúe modificando el receptor.java sobre la base del "Experimento 1".
public void run () {readMessageOnce (); // readMessageContinued ();} Modificado a
public void run () {// readMessageOnce (); readMessageContinued ();} En este momento, el programa puede ejecutarse normalmente. El resultado de la ejecución es: