| Channel | 用途 | 特殊能力 |
| FileChannel | 文件隨機讀寫 | transferTo/From 零拷貝, map 內存映射, lock 文件鎖 |
| SocketChannel | TCP 客戶端 | 非阻塞連接/讀寫 |
| ServerSocketChannel | TCP 服務端 | accept 產生 SocketChannel |
| DatagramChannel | UDP | receive/send 包含地址 |
| Pipe.SinkChannel/SourceChannel | 線程間管道 | 單向,同進程 |
三、交互標準模式
1. 讀取(Channel → Buffer)
ByteBuffer buf = ByteBuffer.allocate(1024);
int bytesRead;
while ((bytesRead = channel.read(buf)) != -1) {
buf.flip(); // 切讀模式
while (buf.hasRemaining()) {
process(buf.get()); // 消費數據
}
buf.clear(); // 切寫模式,備下輪
}
2. 寫入(Buffer → Channel)
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(data);
buf.flip(); // 切讀模式供 Channel 消費
while (buf.hasRemaining()) {
channel.write(buf); // 可能部分寫入,需迴圈
}
buf.clear();
3. 分散/聚集
// 讀取到多個 Buffer(分散)
ByteBuffer[] bufs = { headerBuf, bodyBuf };
channel.read(bufs);
// 從多個 Buffer 寫入(聚集)
channel.write(bufs);
適用於協議頭/體分離處理,減少系統調用與內存拷貝。
四、直接緩衝區 vs 堆緩衝區
| 堆緩衝區 | 直接緩衝區 |
| 分配 | allocate() | allocateDirect() |
| 內存區域 | JVM 堆 | 堆外(OS 原生) |
| GC 壓力 | 有 | 無(需手動清理或靠 DirectByteBuffer 清理器) |
| I/O 性能 | 需拷貝到堆外再寫入 | 零拷貝,DMA 直接讀寫 |
| 分配/釋放開銷 | 低 | 高 |
經驗:長生命周期、大數據量、高頻 I/O 用直接緩衝區;短暫小對象用堆緩衝區。
五、常見坑點
- 忘記
flip() 導致讀取 0 字節。
compact() 未處理未讀數據覆蓋風險。
- 直接緩衝區泄漏(未及時釋放 → OOM),可用
Cleaner 或反射釋放。
- 非阻塞 Channel
read() 返回 0 而非 -1,不可視為 EOF。
- 上一篇文章: Java I/O 體系全景:從傳統流到 NIO 零拷貝原理
- 下一篇文章: NIO 進階概念全景:選擇器、文件鎖、內存映射與虛擬內存原理
Copyright ©
程式碼之家 All Rights Reserved