一、 Java NIO和傳統IO的對比
比對項 | 傳統IO | NIO(Non-Block IO) |
---|---|---|
緩沖 | 面向流 | 面向塊(緩沖) |
IO模型 | 阻塞IO | 非阻塞IO |
線程複用 | 無 | 選擇器 |
二、 java NIO類庫簡介
2.1 Buffer緩沖區(特點:面向塊)
傳統JavaIO是面向流的I/O。流I/O一次處理一個位元組。NIO則是面向塊的I/O,每次操作都是以資料塊為機關。它們的差距就好象兩個人吃飯,一個人一粒一粒的吃,另一個人狼吞虎咽,快慢顯而易見。NIO中引入了緩沖區(Buffer)的概念,緩沖區作為傳輸資料的基本機關:塊。Buffer緩沖區的引入,是NIO與傳統IO的一個重要差別.在傳統IO中,都是針對流資料的操作,在NIO中是針對緩沖區資料操作。
緩沖區的實質是一個數組,最常用的是ByteBuffer.事實上每一種java基本類型都對應一種緩沖區類型.
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICMyYTMvw1dvwlMvwlM3VWaWV2Zh1Wa-cmbw5CZ5MGdzIWZotGdvwFMwEDM5MTMtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
2.2 Channel通道
Channel是資料通道,它與傳統IO Stream的主要差別在于通道是雙向讀寫的,流隻是朝着一個方向移動
Channel可以主要分為2大類:一類為網絡資料讀寫的SelectableChannel和檔案讀寫的FileChannel.
2.3 多路複用器選擇器Selector
Selector類是NIO的核心類,Selector能夠檢測多個注冊的通道上,是否有事件發生,如果有事件發生,便擷取事件然後針對每個事件進行相應的響應處理。這樣一來,隻是用一個單線程就可以管理多個通道,也就是管理多個連接配接。這樣使得隻有在連接配接真正有讀寫事件發生時,才會調用函數來進行讀寫,就大大地減少了系統開銷,并且不必為每個連接配接都建立一個線程,不用去維護多個線程,并且避免了多線程之間的上下文切換導緻的開銷。
2.4 檔案鎖定,記憶體映射等其他新特性
- 檔案鎖定是多個程序協同工作的情況下,要協調程序間對共享資料的通路必不可少的工具。
- 記憶體映射利用虛拟記憶體技術提供對檔案的高速緩存,使讀取磁盤檔案就像從記憶體中讀取一樣高效,但是卻不會有記憶體洩漏的危險,因為在記憶體中不會存在檔案的完整拷貝。
三、 IO模型
JDK4提供了非阻塞IO的能力,JDK7開始提供異步IO能力(NIO2.0)
3.1 阻塞I/O
- 同步阻塞IO
在資料沒有讀寫完成之前,線程不可以進行下一步操作,這樣線程隻好眼睜睜的在那裡傻等。
下圖為采用阻塞IO的通訊模型的服務端,由一個Acceptor監聽用戶端的連結,它接收到用戶端的請求後建立一個新的線程進行鍊路處理,通過輸出流應答用戶端,線程銷毀。簡單地說就是,一用戶端請求對應一個線程.
這個模型有一個很大的問題,就是當用戶端請求規模較大的時候,一用戶端請求建立一個線程,導緻伺服器資源消耗殆盡,造成當機。
- 僞異步IO(線程池)
為了解決這個問題,在服務端使用線程池。線程的數量是固定的(線程池),使用的時候借用擷取,用完之後不是銷毀而是将線程歸還給線程池。但這個解決方案,在并發量超過線程池内現成的數量時,會導緻擷取線程的時間拉長,應答緩慢,延遲較大!這個方案,我們稱為"僞異步IO"!
3.2 非阻塞I/O(Non-Block IO)
- 傳統JavaIO是基于阻塞I/O模型的:當發起一個I/O請求時,如果資料沒有準備好(read時無可讀資料,write時資料不可寫入),那麼線程便會阻塞,直到資料準備好,導緻線程大部分的時間都在阻塞。
- 非阻塞I/O則允許線程在有資料的時候處理資料,沒有資料的時候釋放CPU資源,提高了資源使用率。在資料沒有準備好之前,調用線程可以離開,隻需要每隔一段時間回來詢問一次。
3.3 異步I/O
在資料沒有讀寫完成之前,調用線程可以離開也不用輪詢。在資料準備好之後,多路複用監聽會主動通知調用線程。這通常需要複雜的設計,為降低NIO與AIO的實作複雜度,我們可以使用Netty或者mina等架構。
喜歡 (9)or分享 (0)