Java之NIO解析

NIO初識:

       Java NIO即Java Non-blocking IO(Java非阻塞I/O),因爲是在Jdk1.4之後增加的一套新的操作I/O工具包,所以一般會被叫做Java New IO。NIO是通過Reactor模式的事件驅動機制來達到Non blocking的,那麼什麼是Reactor模式呢?Reactor翻譯成中文是“反應器”,就是我們將事件註冊到Reactor中,當有相應的事件發生時,Reactor便會告知我們有哪些事件發生了,我們再根據具體的事件去做相應的處理。

      NIO 是一種同步非阻塞的 IO 模型。同步是指線程不斷輪詢 IO 事件是否就緒,非阻塞是指線程在等待 IO 的時候,可以同時做其他任務。同步的核心就是 Selector,Selector 代替了線程本身輪詢 IO 事件,避免了阻塞同時減少了不必要的線程消耗;非阻塞的核心就是通道和緩衝區,當 IO 事件就緒時,可以通過寫道緩衝區,保證 IO 的成功,而無需線程阻塞式地等待。

     NIO有三個核心模塊:Selector(選擇器)、Channel(通道)、Buffer(緩衝區);

Buffer(緩衝區)

      當我們需要與 NIO Channel 進行交互時, 我們就需要使用到 NIO Buffer, 即數據從 Buffer讀取到 Channel 中, 並且從 Channel 中寫入到 Buffer 中。緩衝區本質上是一塊可以寫入數據,然後可以從中讀取數據的內存。這塊內存被包裝成NIO Buffer對象,並提供了一組方法,用來方便的訪問該塊內存。

緩衝區基本類型:ByteBuffer;CharBuffer;ShortBuffer;IntBuffer;LongBuffer;FloatBuffer;DoubleBuffer;

緩衝區屬性:capacity、limit、position、mark,並遵循:capacity>=limit>=position>=mark>=0,下面是屬性的解釋:

  • Capacity:     容量,即可以容納的最大數據量;在緩衝區創建時被設定並且不能改變
  • Limit:           上界,緩衝區中當前數據量
  • Position:      位置,下一個要被讀或寫的元素的索引
  • Mark:           標記,調用mark()來設置mark=position,再調用reset()可以讓position恢復到標記的位置即position=mark

Channel(通道):

       通道是對原 I/O 包中的流的模擬。到任何目的地(或來自任何地方)的所有數據都必須通過一個 Channel 對象。一個 Buffer 實質上是一個容器對象。發送給一個通道的所有對象都必須首先放到緩衝區中;同樣地,從通道中讀取的任何數據都要讀到緩衝區中。

      通道是訪問I/O服務的導管。I/O可以分爲廣義的兩大類別:File I/O和Stream I/O。那麼相應地有兩種類型的通道也就不足爲怪了,它們是文件(file)通道和套接字(socket)通道。我們看到在api裏有一個FileChannel類和三個socket通道類:SocketChannel、ServerSocketChannel和DatagramChannel。

Selector(選擇器):

       在併發型服務器程序中使用NIO,實際上是通過網絡事件驅動模型實現的。我們應用Select 機制,不用爲每一個客戶端連接新啓線程處理,而是將其註冊到特定的Selector 對象上,這就可以在單線程中利用Selector 對象管理大量併發的網絡連接,更好的利用了系統資源;採用非阻塞I/O的通信方式,不要求阻塞等待I/O 操作完成即可返回,從而減少了管理I/O 連接導致的系統開銷,大幅度提高了系統性能。

       當有讀或寫等任何註冊的事件發生時,可以從Selector 中獲得相應的SelectionKey , 從SelectionKey 中可以找到發生的事件和該事件所發生的具體的SelectableChannel,以獲得客戶端發送過來的數據。由於在非阻塞網絡I/O 中採用了事件觸發機制,處理程序可以得到系統的主動通知,從而可以實現底層網絡I/O無阻塞、流暢地讀寫,而不像在原來的阻塞模式下處理程序需要不斷循環等待。使用NIO,可以編寫出性能更好、更易擴展的併發型服務器程序。

      通道和緩衝區的機制,使得線程無需阻塞地等待IO事件的就緒,但是總是要有人來監管這些IO事件。這個工作就交給了selector來完成,這就是所謂的同步。

      Selector允許單線程處理多個 Channel。如果你的應用打開了多個連接(通道),但每個連接的流量都很低,使用Selector就會很方便。

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

    Selector中註冊的感興趣事件有:

  • OP_ACCEPT:即連接事件(TCP 連接), 對應於SelectionKey.OP_CONNECT;

  • OP_CONNECT :即確認事件, 對應於SelectionKey.OP_ACCEPT;

  • OP_READ :即讀事件, 對應於SelectionKey.OP_READ, 表示 buffer 可讀.

  • OP_WRITE:即寫事件, 對應於SelectionKey.OP_WRITE, 表示 buffer 可寫.

NIO和IO的主要區別:

  1. IO是面向流的,NIO是面向緩衝的;
  2. IO是阻塞的,NIO是非阻塞的;
  3. IO是單線程的,NIO 是通過選擇器來模擬多線程的;
面向流和麪向緩衝區:

       Java NIO和IO之間第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。 Java IO面向流意味着每次從流中讀一個或多個字節,直至讀取所有字節,它們沒有被緩存在任何地方。此外,它不能前後移動流中的數據。如果需要前後移動從流中讀取的數據,需要先將它緩存到一個緩衝區。 Java NIO的緩衝導向方法略有不同。數據讀取到一個它稍後處理的緩衝區,需要時可在緩衝區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩衝區中包含所有您需要處理的數據。而且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區裏尚未處理的數據。

阻塞和非阻塞IO:
      Java IO的各種流是阻塞的。這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據完全寫入。該線程在此期間不能再幹任何事情了。 Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什麼都不會獲取。而不是保持線程阻塞,所以直至數據變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閒時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。

NIO在基礎的IO流上發展處新的特點,分別是:內存映射技術,字符及編碼,非阻塞I/O和文件鎖定

原文借鑑:https://blog.csdn.net/a953713428/article/category/6790236

                 https://www.cnblogs.com/geason/p/5774096.html

                 http://ifeve.com/java-nio-vs-io/

                



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章