第十一節 netty前傳-NIO 和IO對比
IO/">NIO和IO的區別
兩者有兩點最明顯也是最主要的區別
IO:面向流、阻塞模式
NIO:面向緩衝、非阻塞模式
- 對於第一點
第一個重要區別是IO是面向流的,NIO是面向緩衝區的。
面向流的Java IO意味著可以從流中一次讀取一個或多個位元組。 至於用讀取位元組做什麼取決於客戶。 它們不會快取在任何地方。 此外,你無法在流中的資料中前後移動。 如果需要在從流中讀取的資料中前後移動,則需要先將其快取在緩衝區中。
Java NIO的面向緩衝區的方法略有不同。 將資料讀入緩衝區,稍後處理該緩衝區。 客戶可以根據需要在緩衝區中前後移動。 這使得在處理過程中更具靈活性。 但是,還需要檢查緩衝區是否包含完整處理所需的所有資料。 並且,需要確保在將更多資料讀入緩衝區時,不要覆蓋尚未處理的緩衝區中的資料。
- 對於第二點
第二個區別其實和和第一個也有很大關係。java io面向流,這就使得在從流中讀寫資料都是阻塞進行,而Java NIO一方面通過Selectors選擇器允許單個執行緒監視多個輸入通道。 也可以使用選擇器註冊多個通道,然後使用單個執行緒“select”已經準備好的通道。 這種選擇器機制使單個執行緒可以輕鬆管理多個通道,另一方面面向緩衝使得java nio的讀寫可以立刻返回(非阻塞)。
相較而言java nio比java io更高效,但同時使用也更為複雜,比如下面例子
我的F:\book下有個a.txt內容如下
aaabbbccc
- 在使用java io模式讀取時
File file=new File("F:\\book\\a.text"); //獲取輸入流 InputStream input = new FileInputStream(file); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); //逐行讀取 String a = reader.readLine(); String b = reader.readLine(); String c = reader.readLine();
- 注意上面得io讀取,因為時阻塞,所以一旦reader.readLine()方法返回,就確定已經讀取了這一行得文字,如果nio中,非阻塞讀取結果可能,下面java nio的實現方式
ByteBuffer buffer = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buffer);
- 注意: 在第二行從channel讀取位元組到ByteBuffer。 當該方法呼叫返回時,我們並不知道所需的所有資料是否都在緩衝區內。 只知道緩衝區包含一些位元組。 所以這種情況下設計nio模式的就會比較複雜,借用之前的部分程式碼片段如下:
ByteBuffer buffer = ByteBuffer.allocate(48); //注意:這個方法會記錄讀取的位置,所以後續讀取不會從頭開始讀取 int bytesRead = fileChannel.read(buffer); System.out.println(bytesRead); //讀取到資料 while(bytesRead != -1) { //反轉後為可以讀取緩衝中的資料 buf.flip(); while(buf.hasRemaining())//position < limit;表示可讀 { //讀取 System.out.print((char)buf.get()); } //沒有可讀資料後,清除已讀資料,從未讀資料之後開始寫入 buf.compact(); //開始繼續讀取 bytesRead = fileChannel.read(buf); }
上面的程式碼也可簡化入下圖:

圖片.png
也是由於nio的非阻塞和選擇器這種特點,可以使得一個單執行緒管理多個通道,同時還可以讓每一個通道使用單獨的執行緒處理業務邏輯
簡化如下:

圖片.png