閱讀本文前,建議你先了解 舊I/O
NIO 是 New I/O 的縮寫,要了解它真正的內涵,須要掌握的知識仍是比較多的。我努力在這幾篇筆記裏,勾勒出整個io的面貌。爲你們的深刻學習鋪路。java
想理解I/O的所有,java的I/O歷史是必需要了解的。java的I/O歷史也從一個側面反應了java的發展史。正則表達式
在這個時期的java中,基本上能夠說沒有完整的I/O支持。由於這一時期的java I/O操做是阻塞的,因此I/O效率是較爲底下的,基本上想要有比較好的I/O解決方案,基本靠本身。這時期java在服務器端一直沒有獲得重用,和糟糕的I/O效率是有很大的關係的。不但I/O弄的很差,並且一系列周邊措施都沒弄好。所支持的字符集編碼有限,常常要進行手工的編碼工做。並且沒有正則表達式,處理數據十分困難。緩存
2002年發佈的java1.4中,非阻塞I/O以JSR-51的身份加入到java語言中。同時字符集的編解碼能力大大提高。並且有了基於perl實現的正則表達式類庫。同時部分舊I/O底層實現,也用新I/O的方式重寫,使得舊I/O的性能也有了提高。終於java在服務器端開始流行了起來。服務器
與此同時,第三方也開始發力。谷歌發佈了Guava類庫,其中的I/O部分,極大的簡化了一些文件的操做和數據的傳輸。同時Trustin Lee領導編寫的nio框架netty與mina也廣爲流傳開來,這對java nio的發展業是有着極大的推進力的。網絡
隨着JSR-203的推出,是咱們在java1.7中見到了NIO2。它爲咱們提供了必非阻塞更增強大的異步I/O操做能力,同時提供了一系列極爲方便的對文件系統和文件屬性進行操做的API。以及更增強大的網絡I/O框架
阻塞I/O、非阻塞I/O、異步I/O之間到底有什麼區別?爲何每一次的進步,都會促使java I/O能力的極大提高?咱們舉一個種菜遊戲的例子。異步
假若有一個種菜遊戲(就跟以前的QQ農場相似),在玩家種菜之後,必須一直呆在那個網頁上,看着菜成熟,才能夠收菜。這是極其浪費時間的,用戶體驗也必定不會好。這個遊戲後來進行了改版,玩家種菜以後不用再一直停留在那個網頁上了,只是須要時不時來看一遍,若是某一次查看時發現菜成熟了,就能夠收菜了。固然,用戶體驗極大的提高了,用戶所浪費的時間也減小了,可是爲了更加提高用戶體驗,遊戲又進行了改版。玩家種菜以後,不用再查看菜是否成熟了,等到菜成熟後,該遊戲會自動給用戶發送一個通知,告訴他,菜已成熟、趕忙來收。這樣用戶的基本上不再用浪費時間了。性能
剛剛例子中的三個遊戲版本,表明了三種I/O。阻塞I/O:在數據沒有讀寫完成以前,CPU不能夠進行下一步操做,這樣CPU只好眼睜睜的在那裏傻等。非阻塞I/O:在數據沒有讀寫完成以前,CPU能夠離開,只須要每隔一段時間詢問一次。異步I/O:在數據沒有讀寫完成以前,CPU能夠離開也不用時不時的關心一下I/O,在數據讀寫完成時,主動通知CPU。三種I/O之間的效率,高低立判。學習
我們以java1.4所提出的非阻塞I/O,爲切入點,開始瞭解全貌。編碼
這三個類構成了非阻塞I/O的核心API。
Buffer譯爲緩存區,它是一塊能夠存儲數據的內存。Channel有點像流,但它可讀可寫、從本地I/O到網絡I/O均可以,絕大多數NIO都從一個Channel開始的,數據能夠從Channel讀到Buffer中,也能夠從Buffer 寫到Channel中。
非阻塞I/O中,CPU能夠在數據沒有讀寫完成以前離開,只須要每隔一段時間詢問一次。詢問數據是否讀寫完成,須要的CPU能力是極小的,但若是CPU常常切換任務所須要的保留現場和恢復現場的時間是較大的。因此能夠就用一個線程來詢問數據是否準備好。一個線程在多個通道內詢問數據是否準備好,就須要管理多個通道的方式,這就是
。
使用Selector,得向Selector註冊Channel,而後調用它的select()方法。這個方法會一直阻塞到某個註冊的通道有事件就緒。一旦這個方法返回,線程就能夠處理這些事件。
說了這麼多,咱們該從什麼地方開始呢? 我們從java7的新文件系統開始吧