JAVANIO學習筆記1-架構簡介

北島知寒發表於2016-10-31

最近專案中遇到不少NIO相關知識,之前對這塊接觸得較少,算是我的一個盲區,打算花點時間學習,簡單做一點個人學習總結。

簡介

NIO(New IO)是JDK1.4以後推出的全新IO API,相比傳統IO方式NIO採用了全新的底層I/O模型。傳統IO的設計概念是面向流,而NIO則是面向塊。簡單點說,傳統I/O是基於位元組的,所有I/O都被視為單個位元組的移動,使用時需先把物件轉換為位元組碼;而NIO是面向塊的,以塊為單位處理資料,每個操作會生成或消費一個塊的資料。從設計理念來看,NIO的操作粒度要比傳統IO大很多,採用這種方式效能有很大提高,但也犧牲了java操作的優雅和簡潔。

核心模組

Java NIO 由以下三個核心模組組成:

  • Selector
  • Channel
  • Buffer

selector_2016_10_29_2_17_48_shanbiao_jsb

Selector

執行緒的花銷很大,selector幫助開發者突破IO的瓶頸,它提供了單執行緒處理多個 Channel的機制。如果你的應用開啟了多個連線(通道),但每個連線的流量都很低,使用Selector就會很方便。

這是在一個單執行緒中使用一個Selector處理3個Channel的圖示:

overview_selectors

要使用Selector,得先向Selector註冊Channel,然後呼叫它的select()方法。這個方法會一直阻塞到某個註冊的通道有事件就緒。一旦這個方法返回,執行緒就可以處理這些事件,事件的例子有如新連線進來,資料接收等。

使用Selector,先得向Selector註冊Channel,然後呼叫它的select()方法,這個方法會一直阻塞直到某個註冊的通道有事件就緒。一旦這個方法返回,執行緒就可以處理這些事件。

Channel

Channel是一個物件,可以通過它讀取和寫入資料,所有的IO在NIO中都從一個Channel 開始。Channel中的資料要麼寫入Buffer,要麼從Buffer讀取。拿 NIO 與原來的 I/O 做個比較,Channel就像是流。所有資料都通過Buffer物件來處理,NIO不會將位元組直接寫入通道中,相反,它是將資料寫入包含一個或者多個位元組的緩衝區。同樣,您不會直接從通道中讀取位元組,而是將資料從通道讀入緩衝區,再從緩衝區獲取這個位元組。
通道與流的不同之處在於通道是雙向的,而流只是在一個方向上移動(一個流必須是 InputStream 或者 OutputStream 的子類), 而 通道可以用於讀、寫或者同時用於讀寫。因此,通道可以比流更好地反映底層作業系統的真實情況。特別是在UNIX模型中,底層作業系統通道是雙向的。

常用的Channel:

  • FileChannel:File
  • DatagramChannel:UDP
  • ScoketChannel:TCP
  • ServerSocketChannel:監聽TCP連線

Buffer

Buffer與Channel的關係如下圖:

scatter

Buffer也是NIO的一個亮點,傳統的IO操作面向資料流,意味著每次從流中讀一個或多個位元組,直至完成,資料沒有被快取在任何地方。NIO操作面向緩衝區,資料從Channel讀取到Buffer緩衝區,隨後在Buffer中處理資料。

Buffer其實就是一塊快取區,內部使用位元組陣列儲存資料,並維護幾個特殊變數,實現資料的反覆利用。

目前Buffer的實現類有以下幾種:

  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer
  • MappedByteBuffer

這些都是抽象類,針對各自的應用場景,下面又有很多子類,功能強大。

思考總結

一般我們在工作中遇到NIO相關的場景時,大多都有封裝好的三方庫,但並不是說就沒必要了解其實現原理,知其然而不知其所以然用著也會心虛。

另外,學習優秀的開源專案是提升個人能力的一個有效方法,研究原始碼可以從以下幾個點入手(個人認為):

  • 架構文件 (在腦中建立框架圖)
  • 示例程式碼與單元測試(知道具體介面使用細節)
  • 具體模組實現程式碼(資料結構 – public方法 – private方法)


相關文章