JAVA NIO個人學習筆記

  NIO即New IO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但實現方式不同,NIO主要用到的是塊,所以NIO的效率要比IO高很多。在Java API中提供了兩套NIO,一套是針對標準輸入輸出NIO,另一套就是網絡編程NIO。

     爲了提高IO速度,在JDK 1.4 中新加入了NIO(New Input/Output)類,引入了一種基於通道(Channel)與緩衝區(Buffer)的I/O 方式,它可以使用Native 函數庫直接分配堆外內存,然後通過一個存儲在Java 堆裏面的DirectByteBuffer 對象作爲這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因爲避免了在Java 堆和Native 堆中來回複製數據。顯然,本機直接內存的分配不會受到Java 堆大小的限制,但是,既然是內存,則肯定還是會受到本機總內存(包括RAM 及SWAP 區或者分頁文件)的大小及處理器尋址空間的限制。

   對於IO和NIO的學習 要先理解幾個概念

用戶空間、內核空間

  現在操作系統都是採用虛擬存儲器,那麼對32位操作系統而言,它的尋址空間(虛擬儲存空間)爲4G(2的32次方)。操作系統的核心是內核,獨立於普通的應用程序,可以訪問受保護的內存空間,也有訪問底層硬件設備的所有權限。爲了保證用戶進程不能直接操作內核,保證內核的安全,操作系統將虛擬空間劃分爲兩個部分,一個部分爲內核空間,一部分爲用戶空間。

  如何分配這兩個空間的大小也是有講究的,如windows 32位操作系統,默認的用戶空間:內核空間的比例是1:1;而在32位Linux系統中的默認比例是3:1(3G用戶空間,1G內核空間)。

進程切換

  爲了控制進程的執行,內核必須要有能力掛起正在CPU上運行的進程,並恢復以前掛起的某個進程的執行。這種行爲成爲進程的切換。任何進程都是在操作系統內核的支持下運行的,是與內核緊密相關的。

同步、異步、阻塞、非阻塞

同步與異步:描述的是用戶線程與內核的交互方式,同步指用戶線程發起IO請求後需要等待或者輪詢內核IO操作完成後才能繼續執行;而異步是指用戶線程發起IO請求後仍然繼續執行,當內核IO操作完成後會通知用戶線程,或者調用用戶線程註冊的回調函數。

同步與異步關注的是消息通知機制,所謂同步,就是在消息發出時,得不到返回值,該“調用”就不返回,但一旦返回,就得到返回值。即調用者主動等待這個“調用”的結果。異步則相反,異步在發出之後,調用會立刻返回,並沒有得到返回結果。即異步調用發出後,被調用者通過狀態,消息或者通過回調函處理這個調用。即去書店買書,我打電話給書店老闆詢問是否有A這本書,並一直等到書店老闆告訴我有或沒有我才掛電話,這是同步;若我打電話給書店老闆詢問是否有A這本書,這時老闆說他去查一下並掛了電話(不返回結果),他過一會會主動打電話給你通知是否有這本書,這裏老闆通過打電話的方式來“回調”。

阻塞與非阻塞:描述是用戶線程調用內核IO操作的方式,阻塞是指IO操作需要徹底完成後才返回到用戶空間;而非阻塞是指IO操作被調用後立即返回給用戶一個狀態值,無需等到IO操作徹底完成。

阻塞與非阻塞從個人的角度出發,比如我打電話給書店老闆詢問是否有A這本書,我在等老闆回我這個過程中”掛起“,直到老闆回我結果,那就是阻塞,反之我在這個過程中去幹別的比如我一邊打電話一邊看電視,直到老闆回我,這就是非阻塞,但我在幹別的時候還要不停地留意check老闆有沒有回我。即阻塞與非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態。




下表總結了Java IO和NIO之間的主要區別:

IO NIO
面向流 面向緩衝
阻塞IO 非阻塞IO
選擇器

 

1、面向流與面向緩衝

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

2、阻塞與非阻塞IO

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

3、選擇器(Selectors)

     Java NIO的選擇器允許一個單獨的線程來監視多個輸入通道,你可以註冊多個通道使用一個選擇器,然後使用一個單獨的線程來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。


NIO可讓您只使用一個(或幾個)單線程管理多個通道(網絡連接或文件),但付出的代價是解析數據可能會比從一個阻塞流中讀取數據更復雜

如果需要管理同時打開的成千上萬個連接,這些連接每次只是發送少量的數據,例如聊天服務器,實現NIO的服務器可能是一個優勢。同樣,如果你需要維持許多打開的連接到其他計算機上,如P2P網絡中,使用一個單獨的線程來管理你所有出站連接,可能是一個優勢。


如果你有少量的連接使用非常高的帶寬,一次發送大量的數據,也許典型的IO服務器實現可能非常契合。

JAVA NIO其內部的IO實現是同步的,採用基於selector實現的事件驅動機制。

select是同步的因爲它對IO的讀寫還是同步阻塞的,只是通過線程複用,將IO的準備時間分離出來。真的進行IO時還得等,即同步非阻塞。

異步網絡 jdk 7已經有支持。你可以參考 AsynchronousServerSocketChannel。這個纔是真正的異步IO,不支持UDP;

 


發佈了27 篇原創文章 · 獲贊 48 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章