PipedOutputStream и PipedInputStream
В Java, PipedOutputStream и PipedInputStream находятся в выходных потоках трубопроводов и входные потоки трубопровода соответственно.
Их функция состоит в том, чтобы позволить многопоточности общаться между потоками через трубопроводы. При использовании конвейера связи PipedOutputStream и PipedInputStream должны использоваться в сочетании друг с другом.
При использовании коммуникации трубопровода общий процесс: мы записываем данные в PipedOutputStream в потоке A, и эти данные будут автоматически отправляться в PipedInptream, соответствующий PipedOutputStream, а затем хранятся в буфере PipedInptream; В настоящее время нить B считывает данные в PipedInputStream. Это может реализовать связь между потоком A и потоком B.
Ниже мы смотрим на пример связи через трубопроводы в многопользовании. Примеры включают 3 класса: receiver.java, pipedstreamtest.java и sender.java.
Кодекс приемника. Java выглядит следующим образом:
импортировать java.io.ioexception; Импорт java.io.pipedinputstream; @Suppresswarnings ("all") / *** Поток приемника* / Общедоступный приемник Extends Extens {// Объект ввода трубопровода. // Он связан с объектом «PipedOutputStream», // это позволяет получать данные «PipedOutputStream», а затем позволить пользователю его прочитать. частное PipedInputStream in = new PipedInputStream (); // Получить объект «Поток ввода трубы» общедоступный PipedInputStream getInputStream () {return in; } @Override public void run () {readmessageOnce (); // readmessageContinued (); } // Читать данные один раз из «Входного потока трубы» public void readmessageOnce () {// Хотя размер BUF составляет 2048 байт, он будет читать только 1024 байта из «Входного потока трубы». // Поскольку размер буфера «входного потока трубы» по умолчанию составляет всего 1024 байта. byte [] buf = new Byte [2048]; try {int len = in.read (buf); System.out.println (New String (Buf, 0, Len)); in.close (); } catch (ioException e) {e.printstackTrace (); }} // При чтении> 1024 байт из «Поток ввода трубы», перестаньте читать public void readmessageContinued () {int otto = 0; while (true) {byte [] buf = new Byte [1024]; try {int len = in.read (buf); Всего += Лен; System.out.println (New String (Buf, 0, Len)); // Если общее количество чтения байтов составляет> 1024, выйдите из цикла. if (total> 1024) перерыв; } catch (ioException e) {e.printstackTrace (); }} try {in.close (); } catch (ioException e) {e.printstackTrace (); }}} Код отправителя. Java выглядит следующим образом:
импортировать java.io.ioexception; Импорт java.io.pipedOutputStream; @Suppresswarnings ("all")/ *** Поток отправителя*/ public class sender extends {// Объект выходного потока трубопровода. // Он связан с объектом «PipedInputStream», // это позволяет отправлять данные в данные «PipedInputStream», и затем пользователь может прочитать данные из «PipedInputStream». pripiceOutputStream Out = new PipedOutputStream (); // Получить объект «Поток вывода трубы» publicOutputStream getOutputStream () {return Out; } @Override public void run () {wriseShortMessage (); // writelongmessage (); } // Напишите короткое сообщение в «Поток вывода трубы»: «Это короткое сообщение« Private void writeshortMessage () {string strinfo = »это короткое сообщение»; try {out.write (strinfo.getbytes ()); out.close (); } catch (ioException e) {e.printstackTrace (); }} // Написать длинное сообщение в «Поток вывода трубы» private void writelongmessage () {stringBuilder sb = new StringBuilder (); // Написать 1020 байтов через петлю для (int i = 0; i <102; i ++) sb.append ("0123456789"); // написать 26 байтов больше. sb.append ("abcdefghijklmnopqrstuvwxyz"); // Общая длина STR составляет 1020+26 = 1046 байт string str = sb.toString (); попробуйте {// написать 1046 байтов в «выходной поток трубы» out.write (str.getbytes ()); out.close (); } catch (ioException e) {e.printstackTrace (); }}} Код PipedstreamTest.java выглядит следующим образом:
Импорт java.io.pipedinptstream; import java.io.pipedoutputstream; import java.io.ioexception; @suppresswarnings ("all") / *** Интерактивная программа для входного потока трубопровода и вывода трубопровода* / public pipedstreamtest {public Static void main (string [] rags) {sender t1 = newerer ();); Приемник T2 = новый приемник (); PipedOutputStream Out = t1.getOutputStream (); PipedInputStream in = t2.getInputStream (); Попробуйте {// трубопровод. Суть следующих двух предложений одинакова. //out.connect(in); in.connect (out); /** * Запуск метод потока класса: * Сделайте поток начать выполнение; Виртуальная машина Java вызывает метод запуска потока. * Результатом является то, что два потока работают одновременно; Текущий поток (возвращается из вызова в метод запуска) и другой поток (выполнение метода выполнения). * Незаконно запускать поток несколько раз. Особенно, когда поток закончил выполнение, его нельзя перезапустить. */ t1.start (); t2.start (); } catch (ioException e) {e.printstackTrace (); }}} Результаты работы:
Это короткое сообщение
иллюстрировать:
(1) in.connect (out); Свяжится «Поток ввода трубы» и «выходной поток трубы». Проверьте исходный код connect () в PipedOutputStream.java и PipedInputStream.java; мы знаем. Concect (in); эквивалентен in.connect (out);
(2)
t1.start (); // запустить поток "отправителя" t2.start (); // запустить поток "приемника"
Сначала проверьте исходный код Sender.java и выполните функцию run () после запуска потока; в run () sender.java, call writeshortmessage ();
Функция writeshortmessage (); состоит в том, чтобы написать данные «это короткое сообщение» для «потока вывода трубы»; Эти данные будут получены «Поток ввода трубы». Посмотрим, как это достигнуто.
Давайте сначала посмотрим на исходный код записи (байт B []) и определим его в outputStream.java. PipedOutputStream.java наследует от outputstream.java; исходный код записи (байт B []) в outputstream.java выглядит следующим образом:
public void write (byte b []) бросает ioException {write (b, 0, b.length);} Фактически, написать (байт B []) - это функция записи вызова (байт B [], int off, int len) в pipedoutputstream.java. Глядя на исходный код записи (байт B [], int off, int len), мы обнаружили, что он назовет раковину. Receive (B, Off, Len); Далее, глядя на определение получения (байт B [], int Off, Int Len), мы знаем, что Since.Receive (b, OFF, Len) - это сохранить данные в «выходном потоке трубы» в буфере «потока ввода трубы». Размер по умолчанию буферного буфера «входного потока трубы» составляет 1024 байта.
На этом этапе мы знаем, что: t1.start () запускает поток отправителя, и поток отправителя напишет данные «Это короткое сообщение» в «Поток вывода трубы»; А «выходной поток трубы» будет передавать данные в «Входной поток трубы», то есть он будет сохранен в буфере «Входного потока трубы».
Далее мы смотрим на «как пользователи читают данные из буфера« входного потока труб »». Это на самом деле действие поток приемника.
t2.start () запустит поток приемника, тем самым выполнив функцию receiver.java run (). Глядя на исходный код приемника.
readmessageonce () должен вызовать в.
Благодаря вышеуказанному анализу мы уже знаем, что данные в буфере «Поток ввода трубы» в «это» - это короткое сообщение »; Следовательно, данные BUF - это «это короткое сообщение».
Чтобы углубить понимание трубопровода. Мы продолжим следующие два небольших эксперимента.
Эксперимент 1: Измените Sender.java
Воля
public void run () {writeShortMessage (); // writelongmessage ();} Модифицирован на
public void run () {// writeShortMessage (); writelongmessage ();} Запустите программу. Результат работы:
Эти данные записываются в «Поток вывода трубы» через writelongmessage (), а затем перенесены в «входной поток трубы», а затем хранятся в буфере «входного потока трубы»; а затем прочитайте из буфера пользователем.
Затем наблюдайте за исходным кодом writelongmessage (). Мы можем обнаружить, что длина STR составляет 1046 байт, а затем результат бега составляет всего 1024 байта! Почему это происходит?
Причина проста: размер по умолчанию буфера потока ввода трубопровода составляет 1024 байта. Следовательно, максимум, 1024 байта могут быть написаны.
Наблюдая за исходным кодом PipedinputStream.java, мы можем понять более тщательно.
Private Static Final int default_pipe_size = 1024; public pipedinputstream () {initpipe (default_pipe_size);} Конструктор по умолчанию вызовов initpipe (default_pipe_size), и его исходный код заключается в следующем:
private void initpipe (int pipesize) {if (pipesize <= 0) {бросить новый allodalargumentException ("Размер трубы <= 0"); } buffer = new Byte [pipesize];} Исходя из этого, мы можем знать, что размер по умолчанию буферного буфера составляет 1024 байта.
Эксперимент 2: Продолжайте изменять receiver.java на основе «Эксперимент 1»
Воля
public void run () {readmessageonce (); // readmessageContinued ();} Модифицирован на
public void run () {// readmessageonce (); readmessageContinued ();} Запустите программу. Результат работы:
Этот результат - полные данные, записанные в «входной буфер».
Pipedwriter и Pipedreader
PipedWriter - это выходной поток конвейера символов, который унаследован от писателя.
PipedReader - это входной поток конвейера символов, который наследует от писателя.
Функция Pipedwriter и PipedReader заключается в связи между потоками через трубопроводы. При использовании трубопроводной связи, Pipedwriter и PipedReader должны использоваться в сочетании друг с другом.
Ниже мы смотрим на примеры связи через Pipedwriter и Pipedreader в многопоточном состоянии. Примеры включают 3 класса: receiver.java, sender.java и pipetest.java
Кодекс приемника. Java выглядит следующим образом:
импортировать java.io.ioexception; Импорт java.io.pipedreader; @Suppresswarnings ("all") / *** Поток приемника* / Общедоступный приемник Extends Extens {// Объект ввода трубопровода. // Он связан с объектом «Pipedwriter», // это позволяет вам получать данные «Pipedwriter», а затем позволить пользователю его прочитать. частный PipedReader in = new PipedReader (); // Получить «Объект ввода трубы» public PipedReader getReader () {return in; } @Override public void run () {readmessageOnce (); // readmessageContinued (); } // Читать данные один раз из «Входного потока трубы» public void readmessageonce () {// Хотя размер BUF составляет 2048 символов, он будет читать только 1024 символов из «Поток ввода трубы». // Потому что размер буфера «поток ввода трубы» по умолчанию составляет всего 1024 символа. char [] buf = new char [2048]; try {int len = in.read (buf); System.out.println (New String (Buf, 0, Len)); in.close (); } catch (ioException e) {e.printstackTrace (); }} // При чтении> 1024 символов из «Поток ввода труб», перестаньте читать public void readmessageContinued () {int total = 0; while (true) {char [] buf = new char [1024]; try {int len = in.read (buf); Всего += Лен; System.out.println (New String (Buf, 0, Len)); // Если общее количество чтения символов составляет> 1024, петля выходит. if (total> 1024) перерыв; } catch (ioException e) {e.printstackTrace (); }} try {in.close (); } catch (ioException e) {e.printstackTrace (); }}} Код отправителя. Java выглядит следующим образом:
импортировать java.io.ioexception; Импорт java.io.pipedwriter; @Suppresswarnings ("all")/ *** Поток отправителя*/ public class sender extends {// Объект выходного потока трубопровода. // Он связан с объектом «PipedReader», // это позволяет отправлять данные в данные «PipedReader», а затем пользователь может прочитать данные из «PipedReader». Частный Pipedwriter Out = new Pipedwriter (); // Получить объект «Поток вывода трубы» publicwriter getWriter () {return Out; } @Override public void run () {wriseShortMessage (); // writelongmessage (); } // Напишите короткое сообщение в «Поток вывода трубы»: «Это короткое сообщение« Private void writeshortMessage () {string strinfo = »это короткое сообщение»; try {out.write (strinfo.tochararray ()); out.close (); } catch (ioException e) {e.printstackTrace (); }} // Написать длинное сообщение в «Поток вывода трубы» private void writelongmessage () {stringBuilder sb = new StringBuilder (); // написать 1020 символов через цикл для (int i = 0; i <102; i ++) sb.append ("0123456789"); // написать 26 символов больше. sb.append ("abcdefghijklmnopqrstuvwxyz"); // Общая длина STR составляет 1020+26 = 1046 символов string str = sb.toString (); попробуйте {// написать 1046 символов в «выходной поток труб» out.write (str); out.close (); } catch (ioException e) {e.printstackTrace (); }}} Кодекс Pipetest.java выглядит следующим образом:
Импорт java.io.pipedreader; import java.io.pipedwriter; import java.io.ioexception; @suppresswarnings ("all") / *** Интерактивная программа для потока ввода трубопровода и вывода трубопровода* / public pipetest {public static void main (String [] args) {Sender T1 = new Sender (); Приемник T2 = новый приемник (); Pipedwriter Out = t1.getWriter (); PipedReader in = t2.getReader (); Попробуйте {// трубопровод. Суть следующих двух предложений одинакова. //out.connect(in); in.connect (out); /** * Запуск метод потока класса: * Сделайте поток начать выполнение; Виртуальная машина Java вызывает метод запуска потока. * Результатом является то, что два потока работают одновременно; Текущий поток (возвращается из вызова в метод запуска) и другой поток (выполнение метода выполнения). * Незаконно запускать поток несколько раз. Особенно, когда поток закончил выполнение, его нельзя перезапустить. */ t1.start (); t2.start (); } catch (ioException e) {e.printstackTrace (); }}} Результаты работы:
Это короткое сообщение
Результаты Описание:
(1)
in.connect (out);
Его функция состоит в том, чтобы связать «поток ввода трубы» и «выходной поток трубы». Проверьте исходный код connect () в pipedwriter.java и pipedreader.java; мы знаем. Concect (in); эквивалентен in.connect (out);
(2)
t1.start (); // запустить поток "отправителя" t2.start (); // запустить поток "приемника"
Сначала проверьте исходный код Sender.java и выполните функцию run () после запуска потока; в run () sender.java, call writeshortmessage ();
Функция writeshortmessage (); состоит в том, чтобы написать данные «это короткое сообщение» для «потока вывода трубы»; Эти данные будут получены «Поток ввода трубы». Посмотрим, как это достигнуто.
Давайте сначала посмотрим на исходный код записи (char char. Pipedwriter.java наследует от writer.java; исходный код записи (char c []) в writer.java выглядит следующим образом:
public void write (char cbuf []) бросает ioexception {write (cbuf, 0, cbuf.length);}
Фактически, написать (char c []) - это функция вызовов (char c [], int off, int len) в pipedwriter.java. Глядя на исходный код записи (char c [], int off, int len), мы обнаружили, что он будет называть раковину. Receive (Cbuf, Off, Len); Далее, глядя на определение получения (char c [], int off, int len), мы знаем, что раковина. Receive (Cbuf, OFF, Len) - это сохранить данные в «Потоке выхода трубы» в буфере «входного потока трубы». Размер по умолчанию буферного буфера «Поток ввода трубы» составляет 1024 символа.
На этом этапе мы знаем, что: t1.start () запускает поток отправителя, и поток отправителя напишет данные «Это короткое сообщение» в «Поток вывода трубы»; А «выходной поток трубы» будет передавать данные в «Входной поток трубы», то есть он будет сохранен в буфере «Входного потока трубы».
Далее мы смотрим на «как пользователи читают данные из буфера« входного потока труб »». Это на самом деле действие поток приемника.
t2.start () запустит поток приемника, тем самым выполнив функцию receiver.java run (). Глядя на исходный код приемника.
readmessageonce () должен вызовать в.
Благодаря вышеуказанному анализу мы уже знаем, что данные в буфере «Поток ввода трубы» в «это» - это короткое сообщение »; Следовательно, данные BUF - это «это короткое сообщение».
Чтобы углубить понимание трубопровода. Мы продолжим следующие два небольших эксперимента.
Эксперимент 1: Измените Sender.java
Воля
public void run () {writeShortMessage (); // writelongmessage ();} Модифицирован на
public void run () {// writeShortMessage (); writelongmessage ();} Запустите программу. Результаты работы следующие:
Из этого мы видим, что программа работает неправильно! Бросить исключение java.io.ioexception: труба закрыта
Почему это происходит?
Я проанализирую поток программы.
(1) в Pipetest подключите входные и выходные трубопроводы через in.connect (out); Затем начните два потока. t1.start () запускает отправитель потока, а T2.start () запускает приемник потока.
(2) После того, как поток отправителя запускается, данные записываются в «Выходной конвейер» через writelongmessage (), и out.write (str.thararray ()) пишет в общей сложности 1046 символов. Согласно исходному коду Pipedwriter, функция write () Pipedwriter вызовет функцию rete () PipedReader. Глядя на функцию PipedReader PipedReader, мы знаем, что PipedReader сохранит принятый буфер данных. Если вы внимательно соблюдаете функцию recept (), существует следующий код:
while (in == out) {if ((readside! = null) &&! readside.isalive ()) {бросить новое ioexception ("труба сломана"); } / * Full: пнуть любого ожидания читателей * / notifyall (); попробуй {подождать (1000); } catch (прерванная экспрессация ex) {бросить новый java.io.ErengrUptOexception (); }} Начальные значения в и выходе находятся в = -1, out = 0 соответственно; в сочетании с вышеизложенным (в == out). Мы знаем, что его значение состоит в том, что каждый раз, когда персонаж записывается в трубопровод, условие в == out выполняется. Затем notifyall () вызывается, чтобы разбудить «поток, который считывает трубопровод».
То есть каждый раз, когда персонаж записывается в трубопровод, он будет блокировать и ждать, пока другие потоки будут читать.
Тем не менее, размер по умолчанию буфера Pipedreader составляет 1024! Тем не менее, в настоящее время есть 1046 данных! Следовательно, не более 1024 символов могут быть написаны за раз.
(03) После того, как поток приемника будет запущен, readmessageonce () будет вызван для чтения потока ввода трубопровода. Чтение 1024 символов будет выполнено, и Close () будет вызвано для закрытия, трубы.
Из анализа (02) и (03) можно увидеть, что отправитель должен написать 1046 символов в трубопровод. Среди них первые 1024 символа (буферная емкость 1024) можно записать нормально, и один читается для каждой записи. Когда написаны 1025 символов, напишите () в Pipedwriter.java все еще называется последовательно; затем eCet () в pipedreader.java называется; В PipedReader.java функция получения (int c) в конечном итоге будет вызвана. В настоящее время поток ввода трубопровода был закрыт, то есть закрыто, поэтому бросает новое ioexception («Coom Locked»).
Мы продолжаем изменять «тест одного», чтобы решить проблему.
Эксперимент 2: Продолжайте изменять receiver.java на основе «Эксперимент 1».
public void run () {readmessageonce (); // readmessageContinued ();} Модифицирован на
public void run () {// readmessageonce (); readmessageContinued ();} В настоящее время программа может работать нормально. Результат работы: