掃二維碼與項目經理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯網交流
本文轉載自微信公眾號「小明菜市場」,作者小明菜市場。轉載本文請聯系小明菜市場公眾號。

前言
Java NIO 需要理解的主要有緩沖區(qū),通道,選擇器,這三個主要的部分。
基礎
用戶空間和內核空間
操作系統(tǒng)為了提供穩(wěn)定性,把虛擬地址空間分為用戶空間和內核空間,其中用戶進程只能操作用戶空間的內容,而內核空間的內容可以操作用戶空間的內容以及用戶空間的內容。
I/O過程中的數據流向
假設我們需要從磁盤中的某個文件讀取數據,進程發(fā)起read系統(tǒng)調用,進入內核狀態(tài),內核會隨即向磁盤控制硬件發(fā)出命令,要求其從磁盤讀取數據,磁盤控制器把數據直接寫入到內核緩沖區(qū)中,隨后內核會吧數據從內核空間的臨時緩沖區(qū)拷貝到用戶緩沖區(qū),進程再次切換回用戶態(tài)繼續(xù)執(zhí)行??偨Y數據流向是:磁盤 -> 內核緩沖區(qū) -> 用戶緩沖區(qū)
內存空間多重映射
對于虛擬地址的空間,一個以上的虛擬地址可以指向同一個物理內存地址。如果用戶空間的虛擬地址和內核空間的虛擬地址映射到同一個物理地址,那么這塊物理地址代表的空間就對內核和用戶進程都可見。便可省去數據在內核緩沖區(qū)和用戶緩沖區(qū)來回復制的開銷。
緩沖區(qū)
Java NIO 數據傳輸過程,數據先放到發(fā)送緩沖區(qū) -> 通過通道發(fā)送到接收端 -> 接受端通道接受數據并填充到接受緩沖區(qū) 所以緩沖區(qū)的作用其實是連接通道作為數據傳輸的目標或者來源。
核心概念
屬性
需要理解Buffer工作機制,需要了解如下幾個屬性
存取
緩沖區(qū)的核心就在于存取操作,buffer提供了相對位置存取和絕對位置存取兩種方式。
代碼如下
- //相對位置存取
- public abstract ByteBuffer put(byte b);
- public abstract byte get();
- //絕對位置存取
- public abstract ByteBuffer put(int index, byte b);
- public abstract byte get(int index);
翻轉
翻轉是 buffer的核心概念,可以理解buffer有兩種模式,寫模式和讀模式。寫模式:我們分配一個緩沖區(qū),然后直接填充數據,讀模式下。我們從頭開始讀取數據。如何從寫模式切換到讀模式,翻轉,翻轉的時候我們用limit記錄待讀取數據的長度,然后把位置置換為0就可以開始讀取數據了。
- public final Buffer flip() {
- //記錄待讀取數據的長度
- limit = position;
- //從頭開始讀取數據
- position = 0;
- mark = -1;
- return this;
- }
demo
- //創(chuàng)建一個緩沖區(qū)
- ByteBuffer buffer = ByteBuffer.allocate(100);
- //寫數據
- for (char c : "hello".toCharArray()) {
- buffer.put((byte) c);
- }
- //翻轉
- buffer.flip();//等價于 buffer.limit(buffer.position()).position(0);
- //讀數據
- while (buffer.hasRemaining()) {
- char c = (char) buffer.get();
- System.out.println(c);
- }
直接緩沖區(qū)
對于一般的I/O過程,數據流向是,磁盤或者網絡 -> 內核臨時緩沖區(qū) -> 用戶空間緩沖區(qū)
直接緩沖區(qū)解決的是內核空間臨時緩沖區(qū)到用戶空間緩沖區(qū)復制這一步耗費的多余。雖然直接緩沖區(qū)是I/O的最佳選擇,但是其比創(chuàng)建非直接緩沖區(qū)將會耗費更大的成本了,所以一般都是直接重復使用。
創(chuàng)建緩沖區(qū)
Buffer不能直接通過構造函數實例化,都是通過靜態(tài)工廠方法創(chuàng)建,下為ByteBuffer的靜態(tài)工廠方法。
- //創(chuàng)建內存緩沖區(qū)
- public static ByteBuffer allocate(int capacity);
- //創(chuàng)建直接緩沖區(qū)
- public static ByteBuffer allocateDirect(int capacity) ;
- public static ByteBuffer wrap(byte[] array, int offset, int length)

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯網交流