1. 程式人生 > >Java NIO系列(一) - 概述

Java NIO系列(一) - 概述

連接 監視 其余 數據類型 靈活性 strong 事情 ont 多線程

前言

Java NIO全稱java non-blocking IO,是指jdk1.4及以上版本裏提供的新api(New IO),為所有的原始類型(boolean類型除外)提供緩存支持數據容器,使用它可以提供非阻塞式高伸縮性網絡

Java NIO提供了與標準IO不同的IO工作方式,ChannelBufferSelector構成了核心的API。其它組件,如PipeFileLock,只不過是與三個核心組件共同使用的工具類

  • 通道和緩沖區 (Channel and Buffer):

標準的IO基於字節流字符流進行單向的數據讀寫操作。而NIO是基於通道(Channel)和緩沖區(Buffer

)進行操作,數據總是從通道讀取緩沖區中,或者從緩沖區寫入通道中。

  • 異步IO (Asynchronous IO):

Java NIO可以讓你異步的使用IO,例如:當線程從通道讀取數據到緩沖區時,線程還是可以進行其他事情;當數據被線程寫入緩沖區時,線程可以繼續處理它。從緩沖區寫入通道也類似。

  • 選擇器 (Selector):

Java NIO引入了選擇器的概念,選擇器用於監聽多個通道的事件(比如:連接打開數據讀取數據寫入)。因此,單個的線程可以監聽多個數據通道。

下面就來詳細介紹Java NIO的相關知識。

正文

1. Java NIO概述

Java NIO由以下幾個核心部分組成:

  • Channel
  • Buffer
  • Selector

1.1. Channel和Buffer

基本上,所有的IO NIO中都從一個Channel`開始:

通道Channel有點像(Stream),兩者可以做個簡單對比:

  • 流是單向的,一個流對象要麽是輸出流、要麽是輸入流
  • 通道是全雙工的,一個通道通常搭配緩存一起使用。數據可以從Channel讀到Buffer中,也可以從Buffer寫到Channel中。

這裏有個圖示:

技術分享圖片

Channel和Buffer`有好幾種類型。

JAVA NIO中的一些主要Channel的實現,主要涵蓋了文件IOUDPTCP的網絡IO

  • FileChannel:從文件
    中讀寫數據
  • ServerSocketChannel:能通過UDP讀寫網絡中的數據
  • SocketChannel:能通過TCP讀寫網絡中的數據
  • DatagramChannel:可以監聽新進來的TCP連接,像Web服務器那樣。對每一個新進來的連接都會創建一個SocketChannel

JAVA NIO中關鍵的Buffer實現,涵蓋了除boolean的其余7基本數據類型(byteshortintlongfloatdoublechar):

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

1.2. Selector

Selector允許單線程處理多個Channel連接事件數據讀寫。如果你的應用打開了多個連接通道),但每個連接的流量都很低,使用Selector就會很方便,例如:一個聊天服務器。

這是在一個單線程中使用一個Selector處理3Channel的圖示:

技術分享圖片

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

事件類型主要包括:新連接進來、數據接收、數據發送等。

2. Java NIO對比IO

上面提到了NIO主要的組件和特性,在實際的IO操作中,應該如何在標準IONIO進行選擇,這裏就需要具體對比兩者的差異,並引入一些概念。

IONIO
底層讀寫實現 面向流讀寫 面向緩沖區讀寫
是否有選擇器 基於選擇器的事件分離
IO是否阻塞 阻塞式IO 非阻塞式IO

2.1. 底層讀寫實現

Java NIOIO之間第一個最大的區別是,IO面向流的,NIO面向緩沖區的。

  • 面向流

Java IO面向流意味著每次從流中讀一個或多個字節,直至讀取所有字節,它們沒有被緩存在任何地方。此外,它不能前後移動流中的數據。如果需要前後移動從流中讀取的數據,需要先將它緩存到一個緩沖區。

  • 面向緩沖區

Java NIO的緩沖導向方法略有不同。數據讀取到一個它稍後處理的緩沖區,需要時可在緩沖區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩沖區中包含所有您需要處理的數據。而且,需確保當更多的數據讀入緩沖區時,不要覆蓋緩沖區裏尚未處理的數據。

2.2. 是否有選擇器

Java NIO選擇器允許一個單獨的線程來監視多個輸入通道

IO的讀寫速度和CPU的處理速度相差了一個數量級,導致IO事件延長了CPU的空閑等待時間,導致性能上的瓶頸。為了盡量的縮短CPU的等待時間,在單個IO操作進行時CPU可以抽出身來去做別的事情(其他IO),NIO引入單線程處理多IO事件的概念,從而充分利用CPU分配的資源。

Java NIO允許已註冊的多個通道使用一個選擇器,然後使用一個單獨的線程來選擇通道。這種選擇機制,使得一個單線程很容易地管理多個通道

2.3. IO是否阻塞

所謂阻塞,就是線程在進行IO操作時,不能抽出身來去幹其他事情,必須等待數據讀寫完成。

  • Java IO的各種流是阻塞的

    • 當一個線程調用read()write()時,該線程被阻塞,直到有一些數據被讀取,或數據完全寫入。該線程在此期間不能再幹任何事情。
  • Java NIO非阻塞的

    • 當監聽某個通道的讀操作事件時,線程向該通道發送請求讀取數據,之後這個線程就可以去幹別的事情。
    • 當監聽某個通道的寫操作事件時,線程向請求向該通道寫入數據,但不需要等待它完全寫入,這個線程同時可以去做別的事情。

    線程通常將非阻塞IO空閑時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入輸出通道(channel)。


歡迎關註技術公眾號: 零壹技術棧

技術分享圖片零壹技術棧

本帳號將持續分享後端技術幹貨,包括虛擬機基礎,多線程編程,高性能框架,異步、緩存和消息中間件,分布式和微服務,架構學習和進階等學習資料和文章。

Java NIO系列(一) - 概述