當學習Java的NIO和IO時,有個問題會跳入腦海當中:何時該用IO,何時用NIO?緩存
下面的章節中筆者會試着分享一些線索,包括二者之間的區別,使用場景以及他們是如何影響代碼設計的。服務器
下面這個表格歸納了NIO和IO的主要差別。咱們會針對每一個差別進行解釋。網絡
IO | NIO |
---|---|
Stream oriented | Buffer oriented |
Blocking IO | No blocking IO |
Selectors |
第一個重大差別是IO是面向流的,而NIO是面向緩存區的。這句話是什麼意思呢?socket
Java IO面向流意思是咱們每次從流當中讀取一個或多個字節。怎麼處理讀取到的字節是咱們本身的事情。他們不會再任何地方緩存。再有就是咱們不能在流數據中向先後移動。若是須要向先後移動讀取位置,那麼咱們須要首先爲它建立一個緩存區。學習
Java NIO是面向緩衝區的,這有些細微差別。數據是被讀取到緩存當中以便後續加工。咱們能夠在緩存中向向後移動。這個特性給咱們處理數據提供了更大的彈性空間。固然咱們任然須要在使用數據前檢查緩存中是否包含咱們須要的全部數據。另外須要確保在往緩存中寫入數據時避免覆蓋了已經寫入可是還未被處理的數據。spa
Java IO的各類流都是阻塞的。這意味着一個線程一旦調用了read(),write()方法,那麼該線程就被阻塞住了,知道讀取到數據或者數據完整寫入了。在此期間線程不能作其餘任何事情。線程
Java NIO的非阻塞模式使得線程能夠經過channel來讀數據,而且是返回當前已有的數據,或者什麼都不返回若是但錢沒有數據可讀的話。這樣一來線程不會被阻塞住,它能夠繼續向下執行。設計
一般線程在調用非阻塞操做後,會通知處理其餘channel上的IO操做。所以一個線程能夠管理多個channel的輸入輸出。code
Java NIO的selector容許一個單一線程監聽多個channel輸入。咱們能夠註冊多個channel到selector上,而後而後用一個線程來挑出一個處於可讀或者可寫狀態的channel。selector機制使得單線程管理過個channel變得容易。server
開發中選擇NIO或者IO會在多方面影響程序設計:
顯而易見使用NIO的API接口和使用IO時是不一樣的。不一樣於直接衝InputStream讀取字節,咱們的數據須要先寫入到buffer中,而後再從buffer中處理它們。
數據的處理方式也隨着是NIO或IO而異。 在IO設計中,咱們從InputStream或者Reader中讀取字節。假設咱們如今須要處理一個按行排列的文本數據,以下:
Name: Anna Age: 25 Email: anna@mailserver.com Phone: 1234567890
這個處理文本行的過程大概是這樣的:
InputStream input = ... ; // get the InputStream from the client socket BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String nameLine = reader.readLine(); String ageLine = reader.readLine(); String emailLine = reader.readLine(); String phoneLine = reader.readLine();
NIO容許咱們只用一條線程來管理多個通道(網絡鏈接或文件),隨之而來的代價是解析數據相對於阻塞流來講可能會變得更加的複雜。
若是你須要同時管理成千上萬的連接,這些連接只發送少許數據,例如聊天服務器,用NIO來實現這個服務器是有優點的。相似的,若是你須要維持大量的連接,例如P2P網絡,用單線程來管理這些 連接也是有優點的。這種單線程多鏈接的設計能夠用下圖描述:
Java NIO: A single thread managing multiple connections
若是連接數不是不少,可是每一個連接的佔用較大帶寬,每次都要發送大量數據,那麼使用傳統的IO設計服務器多是最好的選擇。下面是經典IO服務設計圖:
Java IO: A classic IO server design - one connection handled by one thread.