I/O概念
I/O 就是計算機內存與外部設備之間拷貝數據的過程。是爲了解決內存和外部設備速度差異的問題。
我們平時說的阻塞或非阻塞是指應用程序在發起 I/O 操作時,是立即返回還是等待。
而同步和異步,是指應用程序在與內核通信時,數據從內核空間到應用空間的拷貝,是由內核主動發起還是由應用程序來觸發。
I/O模型
UNIX 系統下的 I/O 模型有 5 種:
- 同步阻塞 I/O:BIO
- 同步非阻塞 I/O:NIO
- I/O 多路複用
- 信號驅動 I/O
- 異步 I/O: N2IO
Tomcat支持的I/O模型有:
-
NIO:非阻塞I/O,採用Java NIO類庫實現。
-
NIO.2:異步I/O,採用JDK 7最新的NIO.2類庫實現。
-
APR:採用Apache可移植運行庫實現,是C/C++編寫的本地庫。
一個進程的地址空間分爲用戶空間和內核空間,用戶線程不能直接訪問內核空間。 當用戶線程發起 I/O 操作後,網絡數據讀取操作會經歷兩個步驟:
- 用戶線程等待內核將數據從網卡拷貝到內核空間。
- 內核將數據從內核空間拷貝到用戶空間。
各種 I/O 模型的區別就是:它們實現這兩個步驟的方式是不一樣的。
同步阻塞 I/O
用戶線程發起 read 調用後就阻塞了,讓出 CPU。內核等待網卡數據到來,把數據從網卡拷貝到內核空間,接着把數據拷貝到用戶空間,再把用戶線程叫醒。
同步非阻塞 I/O
用戶線程不斷的發起 read 調用,數據沒到內核空間時,每次都返回失敗,直到數據到了內核空間,這一次 read 調用後,在等待數據從內核空間拷貝到用戶空間這段時間裏,線程還是阻塞的,等數據到了用戶空間再把線程叫醒。
I/O 多路複用
用戶線程的讀取操作分成兩步了,線程先發起 select 調用,目的是問內核數據準備好了嗎?等內核把數據準備好了,用戶線程再發起 read 調用。在等待數據從內核空間拷貝到用戶空間這段時間裏,線程還是阻塞的。那爲什麼叫 I/O 多路複用呢?因爲一次 select 調用可以向內核查多個數據通道(Channel)的狀態,所以叫多路複用。
異步 I/O
用戶線程發起 read 調用的同時註冊一個回調函數,read 立即返回,等內核將數據準備好後,再調用指定的回調函數完成處理。在這個過程中,用戶線程一直沒有阻塞。
組件實現
- Nio2Endpoint組件:實現異步I/O
- NioEndpoint組件:實現I/O 多路複用模型
特別說明:本文圖片,均引自極客時間。