首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java IO 管道流:PipedInputStream/PipedOutputStream 線程間通信實戰

     編輯:Java 綜合教學

Java IO 管道流:線程間內存通信實戰

什麼是管道流?

PipedInputStream / PipedOutputStream 實現線程間內存級數據傳遞,無需中間字節數組,直接「管道」連接輸出流到輸入流。配合多線程實現生產者-消費者模式,讀取阻塞直到有數據寫入。

核心特點

  • 內存直通,避免磁盤/網絡開銷
  • 線程安全,內部同步
  • 讀端無數據時 read() 阻塞,寫端 write() 可阻塞(緩衝區滿)
  • 必須成對使用,通過 connect() 或構造器綁定

完整代碼實現

import java.io.*;

/** 讀取線程(消費者) */
class ReadPipe implements Runnable {
    private PipedInputStream in;
    public ReadPipe(PipedInputStream in) { this.in = in; }
    
    @Override public void run() {
        System.out.println("【讀線程】啟動,等待數據...");
        byte[] buf = new byte[1024];
        try {
            int len = in.read(buf); // 阻塞直到有數據
            String msg = new String(buf, 0, len);
            System.out.println("【讀線程】收到: " + msg);
            in.close();
        } catch (IOException e) { e.printStackTrace(); }
    }
}

/** 寫入線程(生產者) */
class WritePipe implements Runnable {
    private PipedOutputStream out;
    public WritePipe(PipedOutputStream out) { this.out = out; }
    
    @Override public void run() {
        System.out.println("【寫線程】啟動,5 秒後發送數據...");
        try {
            Thread.sleep(5000); // 模擬延遲
            out.write("我是通過管道流傳遞的數據".getBytes("UTF-8"));
            System.out.println("【寫線程】發送完成");
            out.close();
        } catch (Exception e) { e.printStackTrace(); }
    }
}

/** 主程序:創建管道、啟動線程 */
public class PipeDemo {
    public static void main(String[] args) throws IOException {
        // 1. 創建管道兩端
        PipedInputStream in = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream();
        
        // 2. 連接:輸出流 → 輸入流
        in.connect(out); // 或 new PipedInputStream(out)
        
        // 3. 啟動線程
        new Thread(new ReadPipe(in), "Reader").start();
        new Thread(new WritePipe(out), "Writer").start();
        
        System.out.println("主線程結束,子線程繼續運行...");
    }
}

運行結果

主線程結束,子線程繼續運行...
【讀線程】啟動,等待數據...
【寫線程】啟動,5 秒後發送數據...
【寫線程】發送完成
【讀線程】收到: 我是通過管道流傳遞的數據

管道流運行截圖

關鍵注意事項

  1. 必須先 connect 再啟動線程,否則可能死鎖或拋 IOException: Pipe not connected
  2. 單向通信:一對管道只能單向,雙向需兩對
  3. 緩衝區大小固定:JDK 默認 1024 bytes,可通過構造器 new PipedOutputStream(in, bufferSize) 調整 (JDK 9+)
  4. 關閉順序:寫端關閉後,讀端 read() 返回 -1(EOF),讀端再關閉
  5. 異常處理:斷開連接、線程中斷均需捕獲 IOException/InterruptedException

現代替代方案

方案優勢適用場景
BlockingQueue類型安全、豐富 API (put/take/offer/poll)、可指定容量生產者消費者、任務隊列
CompletableFuture異步組合、回調地獄解決、異常傳播異步計算編排
Reactive Streams (Project Reactor/RxJava)背壓、流操作符、函數式高吞吐異步流處理
管道流流式 API、兼容舊代碼、無第三方依賴輕量級字節流傳遞、重定向 System.in/out

總結

管道流是 JDK 1.1 時代的線程間通信機制,雖然被更高級的併發工具取代,但在流式字節數據傳遞、重定向標準輸入輸出、測試模擬流等場景仍有獨特價值。理解其阻塞語義與連接生命週期,有助於排查舊系統相關問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved