BIO是一個(gè)連接一個(gè)線程。
成都創(chuàng)新互聯(lián)公司主要從事成都網(wǎng)站建設(shè)、網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)湖濱,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220
NIO是一個(gè)請(qǐng)求一個(gè)線程。
AIO是一個(gè)有效請(qǐng)求一個(gè)線程。
先來個(gè)例子理解一下概念,以銀行取款為例:
同步 : 自己親自出馬持銀行卡到銀行取錢(使用同步IO時(shí),Java自己處理IO讀寫);
異步 : 委托一小弟拿銀行卡到銀行取錢,然后給你(使用異步IO時(shí),Java將IO讀寫委托給OS處理,需要將數(shù)據(jù)緩沖區(qū)地址和大小傳給OS(銀行卡和密碼),OS需要支持異步IO操作API);
阻塞 : ATM排隊(duì)取款,你只能等待(使用阻塞IO時(shí),Java調(diào)用會(huì)一直阻塞到讀寫完成才返回);
非阻塞 : 柜臺(tái)取款,取個(gè)號(hào),然后坐在椅子上做其它事,等號(hào)廣播會(huì)通知你辦理,沒到號(hào)你就不能去,你可以不斷問大堂經(jīng)理排到了沒有,大堂經(jīng)理如果說還沒到你就不能去(使用非阻塞IO時(shí),如果不能讀寫Java調(diào)用會(huì)馬上返回,當(dāng)IO事件分發(fā)器會(huì)通知可讀寫時(shí)再繼續(xù)進(jìn)行讀寫,不斷循環(huán)直到讀寫完成)
Java對(duì)BIO、NIO、AIO的支持:
Java BIO : 同步并阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)連接一個(gè)線程,即客戶端有連接請(qǐng)求時(shí)服務(wù)器端就需要啟動(dòng)一個(gè)線程進(jìn)行處理,如果這個(gè)連接不做任何事情會(huì)造成不必要的線程開銷,當(dāng)然可以通過線程池機(jī)制改善。
Java NIO : 同步非阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)請(qǐng)求一個(gè)線程,即客戶端發(fā)送的連接請(qǐng)求都會(huì)注冊(cè)到多路復(fù)用器上,多路復(fù)用器輪詢到連接有I/O請(qǐng)求時(shí)才啟動(dòng)一個(gè)線程進(jìn)行處理。
Java AIO(NIO.2) : 異步非阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)有效請(qǐng)求一個(gè)線程,客戶端的I/O請(qǐng)求都是由OS先完成了再通知服務(wù)器應(yīng)用去啟動(dòng)線程進(jìn)行處理,
Java中的IO方式主要分為3種:BIO(同步阻塞)、NIO(同步非阻塞)和AIO(異步非阻塞)。
BIO
同步阻塞模式。在JDK1.4以前,使用Java建立網(wǎng)絡(luò)連接時(shí),只能采用BIO方式,在服務(wù)器端啟動(dòng)一個(gè)ServerSocket,然后使用accept等待客戶端請(qǐng)求,對(duì)于每一個(gè)請(qǐng)求,使用一個(gè)線程來進(jìn)行處理用戶請(qǐng)求。線程的大部分時(shí)間都在等待請(qǐng)求的到來和IO操作,利用率很低。而且線程的開銷比較大,數(shù)量有限,因此服務(wù)器同時(shí)能處理的連接數(shù)也很低。
NIO
BIO模式中,是“一個(gè)Socket一個(gè)線程”;而在NIO中則是使用單個(gè)或少量的線程來輪詢Socket,當(dāng)發(fā)現(xiàn)Socket上有請(qǐng)求時(shí),才為請(qǐng)求分配線程。因此是“一個(gè)請(qǐng)求一個(gè)線程”。
具體實(shí)現(xiàn)就是把Socket通過Channel注冊(cè)到Selector,使用一個(gè)線程在Selector中輪詢,發(fā)現(xiàn)Channel有讀寫的事件,就可以分配給其他線程來處理(通常使用線程池)。
AIO
從JDK7開始支持AIO模式。通過AsynchronousServerSocketChannel中注冊(cè)事件回調(diào)函數(shù)來處理業(yè)務(wù)邏輯。當(dāng)IO操作完成以后,回調(diào)函數(shù)會(huì)被調(diào)用。如果傳入AsynchronousChannelGroup,可以綁定線程池來處理事件。
關(guān)于JDK的實(shí)現(xiàn),Windows平臺(tái)基于IOCP實(shí)現(xiàn)AIO,Linux只有eppoll模擬實(shí)現(xiàn)了AIO。
附:關(guān)于IO經(jīng)常提到Reactor/ Proactor模式。
這兩個(gè)模式中都有兩個(gè)角色:事件多路分離器(Event Demultiplexer)和事件處理器(Event Handler)。分離器負(fù)責(zé)對(duì)監(jiān)聽I(yíng)O事件,并通知處理器;處理器負(fù)責(zé)對(duì)IO內(nèi)容進(jìn)行處理,完成對(duì)應(yīng)的業(yè)務(wù)。
二者的差異,以讀操作為例(寫操作類似)。
Reactor中實(shí)現(xiàn)讀:
1.????????注冊(cè)讀就緒事件和相應(yīng)的事件處理器。
2.????????事件分離器等待事件。
3.????????事件到來,激活分離器,分離器調(diào)用對(duì)應(yīng)的處理器。
4.????????處理器完成IO讀操作,處理讀到的數(shù)據(jù),注冊(cè)新的事件,然后返還控制權(quán)。
Proactor中實(shí)現(xiàn)讀:
1.????????注冊(cè)讀完成事件和相應(yīng)的事件處理器(包括緩沖區(qū)地址)。
2.????????事件分離器等待操作完成事件的同時(shí),操作系統(tǒng)利用并行的內(nèi)核線程執(zhí)行實(shí)際的讀操作,并將結(jié)果數(shù)據(jù)存入用戶自定義緩沖區(qū),最后通知事件分離器讀操作完成。
3.????????事件分離器呼喚處理器。
4.????????事件處理器處理用戶自定義緩沖區(qū)中的數(shù)據(jù),然后啟動(dòng)一個(gè)新的異步操作,并將控制權(quán)返回事件分離器。
由此可見,兩者的主要區(qū)別:Reactor中,由用戶線程(事件處理器所在線程)完成IO的讀寫操作;而在Proactor中,是由操作系統(tǒng)完成IO讀寫操作后,再通知事件處理器,用戶線程只完成對(duì)數(shù)據(jù)的業(yè)務(wù)邏輯處理部分。
更多問題可以問遠(yuǎn)標(biāo)教育中心的技術(shù)咨詢。
Reactor and Proactor
IO讀寫時(shí),多路復(fù)用機(jī)制都會(huì)依賴對(duì)一個(gè)事件多路分離器,負(fù)責(zé)把源事件的IO 事件分離出來,分別到相應(yīng)的read/write事件分離器。涉及到事件分離器的兩種模式分別就是 Reactor和Proactor,Reactor是基于同步IO的,Proactor是基于異步IO的。
在Reactor模式中,事件分離者等待某個(gè)事件或者可應(yīng)用或個(gè)操作的狀態(tài)發(fā)生(比如文件描述符可讀寫,或者是socket可讀寫),事件分離者就把這個(gè)事件傳給事先注冊(cè)的事件處理函數(shù)或者回調(diào)函數(shù),由后者來做實(shí)際的讀寫操作。