1.Java NIO中的同步辰妙、異步、阻塞和非阻塞(非NIO2.0)
在不同的上下文環(huán)境中福荸,Java NIO的模式可以說成是同步肴掷、異步、阻塞台夺、非阻塞颤介,關(guān)注點不同赞赖,結(jié)論不同,本文主要記錄自己的理解辕近。
為什么說是同步
按照UNIX網(wǎng)絡(luò)編程模型的說法移宅,Java NIO使用的I/O復(fù)用模型在select調(diào)用上發(fā)生了阻塞椿疗,因此不屬于異步I/O,參見原文定義:
An asynchronous I/O operation does not cause the requesting process to be blocked.
- 數(shù)據(jù)準(zhǔn)備好(就緒)后浅乔,用戶線程仍需要主動同步進行I/O讀寫操作童擎,而真正的異步I/O模型下攻晒,用戶線程不參與拷貝讀寫鲁捏,如下圖:
-
為什么說是異步
用戶線程注冊事件處理器Selector之后可以繼續(xù)執(zhí)行做其他的工作,而Selector線程負(fù)責(zé)調(diào)用內(nèi)核的select函數(shù)檢查socket狀態(tài)假丧。當(dāng)有socket被激活時包帚,則通知相應(yīng)的用戶線程(或執(zhí)行用戶線程的回調(diào)函數(shù))运吓,執(zhí)行handle_event進行數(shù)據(jù)讀取、處理的工作谋梭。這種通知調(diào)用方式屬于異步調(diào)用瓮床。
NIO類庫支持非阻塞讀和寫操作,相比于同步阻塞讀寫隘庄,是異步的,這里的異步和非阻塞是同義語
-
為什么說是阻塞
-
select調(diào)用是阻塞的贾虽,如下圖:
- NIO類庫也支持通道的阻塞模式(configureBlocking方法設(shè)置為true)蓬豁,但是如果向一個或多個選擇器注冊了此通道地粪,則嘗試將此通道置于阻塞模式將導(dǎo)致拋出 IllegalBlockingModeException蟆技,一般設(shè)置為非阻塞。
-
-
為什么說是非阻塞
- NIO類庫支持非阻塞讀和寫操作质礼,向選擇器selector注冊的通道一般為非阻塞模式
2.關(guān)于非阻塞讀寫
這里所說的非阻塞是針對I/O模型里面的數(shù)據(jù)拷貝階段眶蕉,如recvfrom函數(shù)調(diào)用造挽,而不是非阻塞I/O模型(圖6.6)
這里所說的非阻塞是指socket函數(shù)本身(如recvfrom)可以設(shè)置為阻塞和非阻塞模式弄痹,阻塞模式意味著必須要做完IO操作(包括錯誤)才會返回肛真。 非阻塞模式下無論操作是否完成都會立刻返回,需要通過其他方式來判斷具體操作是否成功
對于讀而言:阻塞和非阻塞I/O的區(qū)別在于沒有數(shù)據(jù)到達(dá)的時候是否立刻返回
對于寫而言:在阻塞I/O的情況是會一直等待直到write完全部的數(shù)據(jù)再返回讥珍,這個和阻塞讀有區(qū)別饭耳。非阻塞寫的情況下寞肖,是采用可以寫多少就寫多少的策略
3. 關(guān)于異步I/O(NIO2.0)
為什么說AIO是真正的異步I/O
當(dāng)用戶線程收到通知時新蟆,數(shù)據(jù)已經(jīng)被內(nèi)核讀取完畢右蕊,并放在了用戶線程指定的緩沖區(qū)內(nèi),內(nèi)核在IO完成后通知用戶線程直接使用即可帕翻,在整個過程中嘀掸,用戶線程除了發(fā)起請求之外未參與任何I/O相關(guān)的操作睬塌,也并未被任何函數(shù)阻塞歇万。AIO與NIO的區(qū)別,在Client端體現(xiàn)為用戶線程得到通知的時間點
在NIO中硫兰,當(dāng)發(fā)生相應(yīng)讀寫事件時瞄崇,用戶線程得到通知,表明數(shù)據(jù)已就緒苏研,開始同步調(diào)用非阻塞讀寫函數(shù)摹蘑,Java API如下:
java.nio.channels.SocketChannel.read(ByteBuffer dst)
java.nio.channels.SocketChannel.write(ByteBuffer src)
在AIO中撒踪,當(dāng)發(fā)生相應(yīng)事件時制妄,用戶線程得到通知耕捞,表明I/O操作已經(jīng)由操作系統(tǒng)異步完成俺抽,用戶線程只需事先向內(nèi)核申明I/O緩沖區(qū)较曼、注冊handler并定義回調(diào)的completed方法即可,Java API如下:
java.nio.channels.AsynchronousSocketChannel.read(ByteBuffer dst, ByteBuffer attachment, CompletionHandler<Integer, ? super ByteBuffer> handler)
java.nio.channels.AsynchronousSocketChannel.write(ByteBuffer src, ByteBuffer attachment, CompletionHandler<Integer, ? super ByteBuffer> handler)
- AIO與NIO的區(qū)別,在Server端體現(xiàn)為Reactor/Proactor的區(qū)別萍歉,在NIO中,監(jiān)控的事件通常為數(shù)據(jù)的到達(dá)横蜒;在AIO中丛晌,監(jiān)控的是事件通常為I/O的完成
4. 參考資料
網(wǎng)絡(luò)編程常見問題總結(jié)
Scalable IO in Java
高性能IO模型淺析
兩種高性能I/O設(shè)計模式(Reactor/Proactor)的比較