亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PipedReader與PipedWriter有哪些不同的地方

發布時間:2020-11-20 15:24:38 來源:億速云 閱讀:149 作者:Leah 欄目:編程語言

這篇文章將為大家詳細講解有關PipedReader與PipedWriter有哪些不同的地方,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

PipedWriter與PipedReader的區別

1. PipedWriter 源碼

package java.io;
 public class PipedWriter extends Writer {
   // 與PipedWriter通信的PipedReader對象
   private PipedReader sink;
   // PipedWriter的關閉標記
   private boolean closed = false;
   // 構造函數,指定配對的PipedReader
   public PipedWriter(PipedReader snk) throws IOException {
     connect(snk);
   }
   // 構造函數
   public PipedWriter() {
   }
   // 將“PipedWriter” 和 “PipedReader”連接。
   public synchronized void connect(PipedReader snk) throws IOException {
     if (snk == null) {
       throw new NullPointerException();
     } else if (sink != null || snk.connected) {
       throw new IOException("Already connected");
     } else if (snk.closedByReader || closed) {
       throw new IOException("Pipe closed");
     }
     sink = snk;
     snk.in = -1;
     snk.out = 0;
     // 設置“PipedReader”和“PipedWriter”為已連接狀態
     // connected是PipedReader中定義的,用于表示“PipedReader和PipedWriter”是否已經連接
     snk.connected = true;
   }
   // 將一個字符c寫入“PipedWriter”中。
   // 將c寫入“PipedWriter”之后,它會將c傳輸給“PipedReader”
   public void write(int c) throws IOException {
     if (sink == null) {
       throw new IOException("Pipe not connected");
     }
     sink.receive(c);
   }
   // 將字符數組b寫入“PipedWriter”中。
   // 將數組b寫入“PipedWriter”之后,它會將其傳輸給“PipedReader”
   public void write(char cbuf[], int off, int len) throws IOException {
     if (sink == null) {
       throw new IOException("Pipe not connected");
     } else if ((off | len | (off + len) | (cbuf.length - (off + len))) < ) {
       throw new IndexOutOfBoundsException();
     }
     sink.receive(cbuf, off, len);
   }
   // 清空“PipedWriter”。
   // 這里會調用“PipedReader”的notifyAll();
   // 目的是讓“PipedReader”放棄對當前資源的占有,讓其它的等待線程(等待讀取PipedWriter的線程)讀取“PipedWriter”的值。
   public synchronized void flush() throws IOException {
     if (sink != null) {
       if (sink.closedByReader || closed) {
         throw new IOException("Pipe closed");
       }
       synchronized (sink) {
         sink.notifyAll();
       }
     }
   }
   // 關閉“PipedWriter”。
   // 關閉之后,會調用receivedLast()通知“PipedReader”它已經關閉。
   public void close() throws IOException {
     closed = true;
     if (sink != null) {
       sink.receivedLast();
     }
   }
 }

2. PipedReader 源碼(基于jdk1.7.40)    

package java.io;
  public class PipedReader extends Reader {
    // “PipedWriter”是否關閉的標記
    boolean closedByWriter = false;
    // “PipedReader”是否關閉的標記
    boolean closedByReader = false;
    // “PipedReader”與“PipedWriter”是否連接的標記
    // 它在PipedWriter的connect()連接函數中被設置為true
   boolean connected = false;
   Thread readSide;  // 讀取“管道”數據的線程
   Thread writeSide;  // 向“管道”寫入數據的線程
   // “管道”的默認大小
  private static final int DEFAULT_PIPE_SIZE = 1024;
   // 緩沖區
   char buffer[];
   //下一個寫入字符的位置。in==out代表滿,說明“寫入的數據”全部被讀取了。
   int in = -;
   //下一個讀取字符的位置。in==out代表滿,說明“寫入的數據”全部被讀取了。
   int out = ;
   // 構造函數:指定與“PipedReader”關聯的“PipedWriter”
   public PipedReader(PipedWriter src) throws IOException {
     this(src, DEFAULT_PIPE_SIZE);
   }
   // 構造函數:指定與“PipedReader”關聯的“PipedWriter”,以及“緩沖區大小”
   public PipedReader(PipedWriter src, int pipeSize) throws IOException {
     initPipe(pipeSize);
     connect(src);
   }
   // 構造函數:默認緩沖區大小是1024字符
   public PipedReader() {
     initPipe(DEFAULT_PIPE_SIZE);
   }
   // 構造函數:指定緩沖區大小是pipeSize
   public PipedReader(int pipeSize) {
     initPipe(pipeSize);
   }
   // 初始化“管道”:新建緩沖區大小
   private void initPipe(int pipeSize) {
    if (pipeSize <= 0) {
       throw new IllegalArgumentException("Pipe size <= 0");
     }
     buffer = new char[pipeSize];
   }
   // 將“PipedReader”和“PipedWriter”綁定。
   // 實際上,這里調用的是PipedWriter的connect()函數
   public void connect(PipedWriter src) throws IOException {
     src.connect(this);
   }
   // 接收int類型的數據b。
   // 它只會在PipedWriter的write(int b)中會被調用
   synchronized void receive(int c) throws IOException {
     // 檢查管道狀態
     if (!connected) {
       throw new IOException("Pipe not connected");
     } else if (closedByWriter || closedByReader) {
       throw new IOException("Pipe closed");
     } else if (readSide != null && !readSide.isAlive()) {
       throw new IOException("Read end dead");
     }
     // 獲取“寫入管道”的線程
     writeSide = Thread.currentThread();
     // 如果“管道中被讀取的數據,等于寫入管道的數據”時,
    // 則每隔1000ms檢查“管道狀態”,并喚醒管道操作:若有“讀取管道數據線程被阻塞”,則喚醒該線程。
     while (in == out) {
       if ((readSide != null) && !readSide.isAlive()) {
         throw new IOException("Pipe broken");
       }
       /* full: kick any waiting readers */
       notifyAll();
       try {
        wait(1000);
       } catch (InterruptedException ex) {
         throw new java.io.InterruptedIOException();
       }
     }
    if (in < 0) {
     in = 0;
      out = 0;
     }
     buffer[in++] = (char) c;
     if (in >= buffer.length) {
      in = 0;
     }
   }
   // 接收字符數組b。
   synchronized void receive(char c[], int off, int len) throws IOException {
     while (--len >= ) {
      receive(c[off++]);
     }
   }
   // 當PipedWriter被關閉時,被調用
   synchronized void receivedLast() {
     closedByWriter = true;
     notifyAll();
   }
   // 從管道(的緩沖)中讀取一個字符,并將其轉換成int類型
   public synchronized int read() throws IOException {
     if (!connected) {
       throw new IOException("Pipe not connected");
     } else if (closedByReader) {
       throw new IOException("Pipe closed");
     } else if (writeSide != null && !writeSide.isAlive()
          && !closedByWriter && (in < )) {
       throw new IOException("Write end dead");
     }
     readSide = Thread.currentThread();
    int trials = 2;
    while (in < 0) {
       if (closedByWriter) {
         /* closed by writer, return EOF */
         return -1;
       }
       if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < )) {
         throw new IOException("Pipe broken");
       }
       /* might be a writer waiting */
       notifyAll();
       try {
        wait(1000);
       } catch (InterruptedException ex) {
         throw new java.io.InterruptedIOException();
       }
     }
     int ret = buffer[out++];
     if (out >= buffer.length) {
      out = 0;
     }
     if (in == out) {
       /* now empty */
      in = -1;
     }
     return ret;
   }
   // 從管道(的緩沖)中讀取數據,并將其存入到數組b中
   public synchronized int read(char cbuf[], int off, int len) throws IOException {
     if (!connected) {
       throw new IOException("Pipe not connected");
     } else if (closedByReader) {
       throw new IOException("Pipe closed");
     } else if (writeSide != null && !writeSide.isAlive()
         && !closedByWriter && (in < 0)) {
       throw new IOException("Write end dead");
     }
    if ((off < 0) || (off > cbuf.length) || (len < 0) ||
      ((off + len) > cbuf.length) || ((off + len) < 0)) {
       throw new IndexOutOfBoundsException();
     } else if (len == 0) {
      return 0;
     }
     /* possibly wait on the first character */
     int c = read();
    if (c < 0) {
      return -1;
     }
     cbuf[off] = (char)c;
    int rlen = 1;
    while ((in >= 0) && (--len > 0)) {
       cbuf[off + rlen] = buffer[out++];
       rlen++;
       if (out >= buffer.length) {
       out = 0;
       }
       if (in == out) {
         /* now empty */
         in = -;
       }
     }
     return rlen;
   }
   // 是否能從管道中讀取下一個數據
   public synchronized boolean ready() throws IOException {
     if (!connected) {
       throw new IOException("Pipe not connected");
     } else if (closedByReader) {
       throw new IOException("Pipe closed");
     } else if (writeSide != null && !writeSide.isAlive()
          && !closedByWriter && (in < )) {
       throw new IOException("Write end dead");
     }
    if (in < 0) {
       return false;
     } else {
       return true;
     }
   }
   // 關閉PipedReader
   public void close() throws IOException {
     in = -;
     closedByReader = true;
   }
 }

示例

下面,我們看看多線程中通過PipedWriter和PipedReader通信的例子。例子中包括3個類:Receiver.java, Sender.java 和 PipeTest.java

Receiver.java的代碼如下:  

 import java.io.IOException;  
 import java.io.PipedReader;  
 @SuppressWarnings("all")  
 /** 
  * 接收者線程 
  */  
 public class Receiver extends Thread {  
   // 管道輸入流對象。
   // 它和“管道輸出流(PipedWriter)”對象綁定,
   // 從而可以接收“管道輸出流”的數據,再讓用戶讀取。
   private 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[];
       try {
         int len = in.read(buf);
         total += len;
         System.out.println(new String(buf,,len));
        // 若讀取的字符總數>1024,則退出循環。
       if (total > 1024)
           break;
       } catch (IOException e) {
         e.printStackTrace();
       }
     }
     try {
       in.close(); 
     } catch (IOException e) {  
       e.printStackTrace();  
     }  
   }  
 }
 
Sender.java的代碼如下:
 
 import java.io.IOException;  
  import java.io.PipedWriter;  
 @SuppressWarnings("all")
 /** 
  * 發送者線程 
  */  
 public class Sender extends Thread {  
   // 管道輸出流對象。
   // 它和“管道輸入流(PipedReader)”對象綁定,
   // 從而可以將數據發送給“管道輸入流”的數據,然后用戶可以從“管道輸入流”讀取數據。
   private PipedWriter out = new PipedWriter();
   // 獲得“管道輸出流”對象
   public PipedWriter getWriter(){
     return out;
   }  
   @Override
   public void run(){  
     writeShortMessage();
     //writeLongMessage();
   }  
   // 向“管道輸出流”中寫入一則較簡短的消息:"this is a short message" 
   private void writeShortMessage() {
     String strInfo = "this is a short message" ;
     try {
       out.write(strInfo.toCharArray());
       out.close();  
     } catch (IOException e) {  
       e.printStackTrace();  
     }  
   }
   // 向“管道輸出流”中寫入一則較長的消息
   private void writeLongMessage() {
     StringBuilder sb = new StringBuilder();
    // 通過for循環寫入1020個字符
     for (int i=0; i<102; i++)
      sb.append("0123456789");
    // 再寫入26個字符。
    sb.append("abcdefghijklmnopqrstuvwxyz");
    // str的總長度是1020+26=1046個字符
    String str = sb.toString();
    try {
      // 將1046個字符寫入到“管道輸出流”中
       out.write(str);
       out.close();
     } catch (IOException e) {
       e.printStackTrace();
     }
   }
 } 

PipeTest.java的代碼如下: 

 import java.io.PipedReader;
 import java.io.PipedWriter;
 import java.io.IOException;
 @SuppressWarnings("all")  
 /** 
  * 管道輸入流和管道輸出流的交互程序
  */  
 public class PipeTest {  
   public static void main(String[] args) {  
    Sender t1 = new Sender();  
   Receiver t2 = new Receiver();  
    PipedWriter out = t1.getWriter();  
     PipedReader in = t2.getReader();  
     try {  
       //管道連接。下面句話的本質是一樣。
       //out.connect(in);  
       in.connect(out);  
       /** 
       * Thread類的START方法: 
       * 使該線程開始執行;Java 虛擬機調用該線程的 run 方法。  
       * 結果是兩個線程并發地運行;當前線程(從調用返回給 start 方法)和另一個線程(執行其 run 方法)。  
       * 多次啟動一個線程是非法的。特別是當線程已經結束執行后,不能再重新啟動。  
       */
       t.start();
       t.start();
     } catch (IOException e) {
       e.printStackTrace();
     }
   }
 }

運行結果:

this is a short message

結果說明:

(01) in.connect(out);

        它的作用是將“管道輸入流”和“管道輸出流”關聯起來。查看PipedWriter.java和PipedReader.java中connect()的源碼;我們知道 out.connect(in); 等價于 in.connect(out);

(02)

t1.start(); // 啟動“Sender”線程
t2.start(); // 啟動“Receiver”線程

先查看Sender.java的源碼,線程啟動后執行run()函數;在Sender.java的run()中,調用writeShortMessage();

writeShortMessage();的作用就是向“管道輸出流”中寫入數據"this is a short message" ;這條數據會被“管道輸入流”接收到。下面看看這是如何實現的。

先看write(char char的源碼。PipedWriter.java繼承于Writer.java;Writer.java中write(char c[])的源碼如下:

public void write(char cbuf[]) throws IOException {
  write(cbuf, 0, cbuf.length);
}

實際上write(char c[])是調用的PipedWriter.java中的write(char c[], int off, int len)函數。查看write(char c[], int off, int len)的源碼,我們發現:它會調用 sink.receive(cbuf, off, len); 進一步查看receive(char c[], int off, int len)的定義,我們知道sink.receive(cbuf, off, len)的作用就是:將“管道輸出流”中的數據保存到“管道輸入流”的緩沖中。而“管道輸入流”的緩沖區buffer的默認大小是1024個字符。

至此,我們知道:t1.start()啟動Sender線程,而Sender線程會將數據"this is a short message"寫入到“管道輸出流”;而“管道輸出流”又會將該數據傳輸給“管道輸入流”,即而保存在“管道輸入流”的緩沖中。

接下來,我們看看“用戶如何從‘管道輸入流'的緩沖中讀取數據”。這實際上就是Receiver線程的動作。

t2.start() 會啟動Receiver線程,從而執行Receiver.java的run()函數。查看Receiver.java的源碼,我們知道run()調用了readMessageOnce()。

而readMessageOnce()就是調用in.read(buf)從“管道輸入流in”中讀取數據,并保存到buf中。

通過上面的分析,我們已經知道“管道輸入流in”的緩沖中的數據是"this is a short message";因此,buf的數據就是"this is a short message"。

為了加深對管道的理解。我們接著進行下面兩個小試驗。

試驗一:修改Sender.java

public void run(){  
  writeShortMessage();
  //writeLongMessage();
}

修改為

public void run(){  
  //writeShortMessage();
  writeLongMessage();
}

運行程序。運行結果如下: 

從中,我們看出,程序運行出錯!拋出異常 java.io.IOException: Pipe closed

為什么會這樣呢?

我分析一下程序流程。

(01) 在PipeTest中,通過in.connect(out)將輸入和輸出管道連接起來;然后,啟動兩個線程。t1.start()啟動了線程Sender,t2.start()啟動了線程Receiver。

(02) Sender線程啟動后,通過writeLongMessage()寫入數據到“輸出管道”,out.write(str.toCharArray())共寫入了1046個字符。而根據PipedWriter的源碼,PipedWriter的write()函數會調用PipedReader的receive()函數。而觀察PipedReader的receive()函數,我們知道,PipedReader會將接受的數據存儲緩沖區。仔細觀察receive()函數,有如下代碼:

while (in == out) {
  if ((readSide != null) && !readSide.isAlive()) {
    throw new IOException("Pipe broken");
  }
  /* full: kick any waiting readers */
  notifyAll();
  try {
    wait(1000);
  } catch (InterruptedException ex) {
    throw new java.io.InterruptedIOException();
  }
}

而in和out的初始值分別是in=-1, out=0;結合上面的while(in==out)。我們知道,它的含義就是,每往管道中寫入一個字符,就達到了in==out這個條件。然后,就調用notifyAll(),喚醒“讀取管道的線程”。
也就是,每往管道中寫入一個字符,都會阻塞式的等待其它線程讀取。

然而,PipedReader的緩沖區的默認大小是1024!但是,此時要寫入的數據卻有1046!所以,一次性最多只能寫入1024個字符。

(03) Receiver線程啟動后,會調用readMessageOnce()讀取管道輸入流。讀取1024個字符會,會調用close()關閉,管道。

由(02)和(03)的分析可知,Sender要往管道寫入1046個字符。其中,前1024個字符(緩沖區容量是1024)能正常寫入,并且每寫入一個就讀取一個。當寫入1025個字符時,依然是依次的調用PipedWriter.java中的write();然后,write()中調用PipedReader.java中的receive();在PipedReader.java中,最終又會調用到receive(int c)函數。 而此時,管道輸入流已經被關閉,也就是closedByReader為true,所以拋出throw new IOException("Pipe closed")。
我們對“試驗一”繼續進行修改,解決該問題。

試驗二: 在“試驗一”的基礎上繼續修改Receiver.java

public void run(){  
  readMessageOnce() ;
  //readMessageContinued() ;
}

修改為

public void run(){  
  //readMessageOnce() ;
  readMessageContinued() ;
}

此時,程序能正常運行。運行結果為:

01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789abcd
efghijklmnopqrstuvwxyz

關于PipedReader與PipedWriter有哪些不同的地方就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

郸城县| 班玛县| 洛南县| 珲春市| 武强县| 福州市| 扶余县| 大田县| 和顺县| 洛南县| 北流市| 即墨市| 永年县| 朝阳县| 澄江县| 花垣县| 托克逊县| 拉萨市| 辽源市| 元谋县| 岱山县| 申扎县| 白山市| 上高县| 海口市| 正定县| 奉化市| 滨州市| 鹤庆县| 左权县| 呼伦贝尔市| 老河口市| 清新县| 县级市| 祥云县| 云龙县| 开远市| 衡阳县| 仙居县| 潜山县| 乌苏市|