1.先說結(jié)論
在討論IO的時候,同步和異步、阻塞和非阻塞是個經(jīng)久不衰的技術(shù)話題。
一個IO操作涉及兩個對象,分別是用戶進(jìn)程(線程)和系統(tǒng)內(nèi)核。
以一個IO read操作為例,經(jīng)歷兩個階段:1.等待數(shù)據(jù)準(zhǔn)備;2.將數(shù)據(jù)從內(nèi)核拷貝到用戶進(jìn)程。
各種IO模式之間的區(qū)別,要從這兩個階段去體會,重點關(guān)注用戶進(jìn)程(線程)是否讓出CPU時間片,數(shù)據(jù)拷貝是由誰來完成。下面說說個人認(rèn)同的理解:
阻塞IO和非阻塞IO,都是同步IO;都是用戶進(jìn)程(線程)從內(nèi)核中把數(shù)據(jù)取走。區(qū)別在于,阻塞IO模式下,用戶進(jìn)程會處于阻塞狀態(tài)(讓出CPU時間片),一直等待內(nèi)核把數(shù)據(jù)準(zhǔn)備好;非阻塞IO模式下,用戶進(jìn)程可以不斷地主動去看數(shù)據(jù)是否準(zhǔn)備好了,期間仍可以占用CPU時間片執(zhí)行其它指令。
異步IO是說用戶進(jìn)程(線程)發(fā)起IO請求,注冊回調(diào)接口,之后就可以執(zhí)行其它指令;由內(nèi)核負(fù)責(zé)調(diào)用回調(diào)接口把數(shù)據(jù)拷貝到用戶進(jìn)程。
2.再看概念
阻塞和非阻塞
阻塞和非阻塞,是針對用戶進(jìn)程(線程)的狀態(tài)來說的。阻塞意味著用戶進(jìn)程(線程)被掛起,即讓出CPU時間片;非阻塞意味著用戶進(jìn)程(線程)不會掛起,仍可以做其它工作。
同步和異步
同步和異步,可以認(rèn)為是針對指令執(zhí)行順序來說的。同步意味著發(fā)起調(diào)用后,沒有得到結(jié)果之前,就不返回,自然不能執(zhí)行其它指令;異步意味著調(diào)用發(fā)出后,調(diào)用方立刻返回,通過回調(diào)等措施拿到結(jié)果,這樣調(diào)用方還可以執(zhí)行其它指令。
因此,可以說阻塞和非阻塞、同步和異步,是針對不同的主體而言的。
3.Java IO
對于java程序員來說,JDK提供了bio、nio和aio,分別對應(yīng)了阻塞IO、非阻塞IO和異步IO。
以網(wǎng)絡(luò)IO的舉例來說,JDK分別提供了以下的API來實現(xiàn)不同的IO模式。
bio
- ServerSocket
- Socket
nio
- ServerSocketChannel
- SocketChannel
- Selector
Java nio通過Selector實現(xiàn)多路復(fù)用IO,使用Reactor模式,具體到linux上,底層是epoll模式。關(guān)于select、poll和epoll的區(qū)別,此處不做討論。
aio
- AsynchronousServerSocketChannel
- AsynchronousSocketChannel
- CompletionHandler
Java aio是Proactor模式,底層實現(xiàn)取決于操作系統(tǒng)是否支持異步IO,支持異步IO的linux版本,提供aio_read和aio_write函數(shù)。