實際工作中,使用Java IO的API來操作文件的機會并不多,更多的時候只需要配置文件(xml , properties)放到指定的位置,剩下的工作就交給框架來處理,框架會把配置數據變成Java對象來調用,不用操心IO細節。
其實IO就是輸入輸出的意思,文件只是一個IO的例子而已。從網絡讀寫數據也是IO,IO是對他們的抽象。
我們把的自己當做是程序,從外面讀數據的時候就用InputStream,向外邊寫數據的時候就用OutputStream
Stream 這個詞也很有意思,想象一下,你從文件 / 網絡讀取數據, 這些數據像河流一樣 “流” 向你, 是不是很形象? 由于是“流”, 你讀到了第 100 個字節, 然后想退回到第 10 個字節重新讀, 那我是不允許的, 河流是不允許倒退的。
但是計算機中的一切都是二進制字節,但是如果直接使用InputStream或者OutputStream來讀文本內容,會有些麻煩,還得翻譯成字符,所以Java提供了Reader/Writer接口,專門用于櫥窗字符流。
## 阻塞
IO API的最大問題在于阻塞,比如讀取文件中的一行數據

當一個線程在執行這段代碼的時候,遇到了readLine()方法的時候,需要等待數據從硬盤進入內存。 這個線程就會被阻塞。
人們想把它改為非阻塞,也就是調用了readLine()之后,立刻就煩這,線程就可以干其他事去了。
但是線程不就是為了讀數據嗎,如果變成了非阻塞,調用了readLine()之后,線程可以執行后面的代碼,那這個線程豈不是還得做個輪詢操作,看看數據是否已讀好了。
要是線程打開了成百上千個文件,使用阻塞的方式,只能按照文件1、文件2這樣的順序去讀取,太慢了,如果是非阻塞二方式可以同時發起成百上千個讀操作,然后在循環中檢查, 看誰的數據處理好了,就讀誰的。
這種情況常見于Socket編程,一個Socket來了,就創建一個新的線程或者從線程池分配一個線程去處理這個連接,要是并發連接太多了,就只能多創建線程。
但是線程太多也有問題,每個線程都會占用內存空間,數量多了系統受不了,線程之間的切換是非常要命。
所以非阻塞的方式比較好,讓一個線程管理成百上千個socket連接,就像管理多個文件一樣,不用做線程的切換。
因為在某一個時刻,不是每個socket都有數據讀寫,很多時候都是空閑的,完全可以用輪詢的方式來查看哪些socket可以讀寫,進行操作。
不過因為Stream,Reader用得太多了,不能輕舉妄動,可以設計一套新的API,叫Java NIO
也就是non-blocking IO
里面有幾個關鍵概念:
* Channel:可以和原來的Steam類比,就是通過Channel讀寫數據,是非阻塞的,一個socket也是channel的一種。
* Buffer:通過Channel讀寫的數據都在Buffer,有于Buffer不是流,讀到Buffer的尾部還可以從頭讀。
* Selector:和Channel配合使用,Channel可以把自己注冊到Selector里面,告訴Selector要監聽XXX事件,這是一個線程可以管理多個 Channel的關鍵

在一個無限循環中讓一個線程處理多個連接
