Java I/O模型

同步 vs. 異步

同步I/O 每個請求必須逐個地被處理,一個請求的處理會導致整個流程的暫時等待,這些事件無法并發(fā)地執(zhí)行。用戶線程發(fā)起I/O請求后需要等待或者輪詢內核I/O操作完成后才能繼續(xù)執(zhí)行。

異步I/O 多個請求可以并發(fā)地執(zhí)行,一個請求或者任務的執(zhí)行不會導致整個流程的暫時等待。用戶線程發(fā)起I/O請求后仍然繼續(xù)執(zhí)行,當內核I/O操作完成后會通知用戶線程,或者調用用戶線程注冊的回調函數。

阻塞 vs. 非阻塞

阻塞 某個請求發(fā)出后,由于該請求操作需要的條件不滿足,請求操作一直阻塞,不會返回,直到條件滿足。

非阻塞 請求發(fā)出后,若該請求需要的條件不滿足,則立即返回一個標志信息告知條件不滿足,而不會一直等待。一般需要通過循環(huán)判斷請求條件是否滿足來獲取請求結果。

需要注意的是,阻塞并不等價于同步,而非阻塞并非等價于異步。事實上這兩組概念描述的是I/O模型中的兩個不同維度。

同步和異步著重點在于多個任務執(zhí)行過程中,后發(fā)起的任務是否必須等先發(fā)起的任務完成之后再進行。而不管先發(fā)起的任務請求是阻塞等待完成,還是立即返回通過循環(huán)等待請求成功。

而阻塞和非阻塞重點在于請求的方法是否立即返回(或者說是否在條件不滿足時被阻塞)。

Unix下五種I/O模型

Unix 下共有五種 I/O 模型:

  • 阻塞 I/O

  • 非阻塞 I/O

  • I/O 多路復用(select和poll)

  • 信號驅動 I/O(SIGIO)

  • 異步 I/O(Posix.1的aio_系列函數)

阻塞I/O

如上文所述,阻塞I/O下請求無法立即完成則保持阻塞。阻塞I/O分為如下兩個階段。

  • 階段1:等待數據就緒。網絡 I/O 的情況就是等待遠端數據陸續(xù)抵達;磁盤I/O的情況就是等待磁盤數據從磁盤上讀取到內核態(tài)內存中。

  • 階段2:數據拷貝。出于系統(tǒng)安全,用戶態(tài)的程序沒有權限直接讀取內核態(tài)內存,因此內核負責把內核態(tài)內存中的數據拷貝一份到用戶態(tài)內存中。

非阻塞I/O

非阻塞I/O請求包含如下三個階段