一、阻塞镣陕?同步征唬?
可能大家平常會(huì)經(jīng)常聽(tīng)到這兩個(gè)名詞,但是沒(méi)花太多心思詳細(xì)了解茁彭,今天就來(lái)揭開(kāi)這層面紗。
一次IO操作扶歪,以read方法舉例理肺,會(huì)經(jīng)歷兩個(gè)階段:
(1)等待數(shù)據(jù)準(zhǔn)備(Waitingfor the data to be ready)
是否阻塞指的就是這一個(gè)階段。
(2)將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程中(Copying the data from the kernel to the process)
是否同步指的就是這一個(gè)階段善镰。
二妹萨、BIO
即blocking IO,阻塞式IO炫欺,大家最為熟悉的IO流乎完,經(jīng)常用于操作網(wǎng)絡(luò)請(qǐng)求,文件讀寫(xiě)之類(lèi)品洛。按讀取類(lèi)型可分為兩大類(lèi):字符流树姨,字節(jié)流。詳情圖如下:
附上普通I/O(BIO)的讀流程圖示:
當(dāng)左邊的應(yīng)用進(jìn)程發(fā)出了“system call”命令后桥状,kernel首先進(jìn)入第一階段“wait for data”帽揪,然后再進(jìn)入第二階段“copying the data”,最后“return OK”返回到用戶(hù)進(jìn)程中辅斟,即BIO在兩個(gè)階段都是阻塞block的转晰,阻塞并同步。
三士飒、NIO
即non-blocking IO查邢,也叫做new IO,因?yàn)槭荖IO是JDK 1.4的java.nio.*包中引入的新I/O庫(kù)酵幕,目的是提高速度扰藕,也是對(duì)之前的BIO一個(gè)補(bǔ)充完善。
NIO的三個(gè)重點(diǎn)裙盾,重中之重的是:
1. channel(通道)
連接data數(shù)據(jù)與buffer緩存區(qū)的橋梁实胸。
- 既可以從通道中讀取數(shù)據(jù),又可以寫(xiě)數(shù)據(jù)到通道番官。但流的讀寫(xiě)通常是單向的庐完。
- 通道可以異步地讀寫(xiě)。
- 通道中的數(shù)據(jù)總是要先讀到一個(gè)Buffer徘熔,或者總是要從一個(gè)Buffer中寫(xiě)入门躯。
2. Buffer(緩沖區(qū))
用于和NIO通道進(jìn)行交互。如圖所示酷师,數(shù)據(jù)是從通道讀入緩沖區(qū)讶凉,從緩沖區(qū)寫(xiě)入到通道中的染乌。
3. Selector(選擇器)
是Java NIO中能夠檢測(cè)一到多個(gè)NIO通道,并能夠知曉通道是否為諸如讀寫(xiě)事件做好準(zhǔn)備的組件懂讯,如此一個(gè)單獨(dú)的線程可以管理多個(gè)channel荷憋,從而管理多個(gè)連接。
由于selector的原因褐望,可以將NIO簡(jiǎn)單區(qū)分為兩種:普通的NIO勒庄,和多路復(fù)用的NIO(加入了selector管理)。通過(guò)下面兩張IO操作圖示簡(jiǎn)單說(shuō)明下兩者區(qū)別:
很明顯的可以觀測(cè)到NIO在IO操作的準(zhǔn)備數(shù)據(jù)階段時(shí)有一個(gè)輪詢(xún)操作瘫里,會(huì)不停地發(fā)出“system call”到kernel輪詢(xún)數(shù)據(jù)是否準(zhǔn)備好实蔽,沒(méi)準(zhǔn)備好,應(yīng)用進(jìn)程可以處理其他事谨读,準(zhǔn)備好了之后在發(fā)出一個(gè)“system call”到kernel進(jìn)行第二個(gè)階段復(fù)制數(shù)據(jù)局装,這個(gè)過(guò)程是blocking的,所以NIO的特點(diǎn)就是在IO執(zhí)行的第一階段不會(huì)阻塞劳殖,但是在第二階段將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程這個(gè)真是的IO操作還是會(huì)阻塞铐尚。
多路復(fù)用的NIO則是上述的普通NIO的補(bǔ)充,在并發(fā)量過(guò)大的情況下哆姻,不可能每個(gè)線程都要輪詢(xún)自己的IO狀態(tài)塑径,這時(shí)就可以使用selector管理所有的IO通道channel,之用開(kāi)啟一個(gè)線程填具,便可解決成千上萬(wàn)的高并發(fā)問(wèn)題(??ˇ?ˇ?)?
四统舀、AIO
NIO 2.0引入了新的異步通道的概念,并提供了對(duì)異步文件通道和異步套接字通道的實(shí)現(xiàn)劳景。(基于NIO)
Asynchronous IO誉简,字面意思即異步的IO,完全不阻塞盟广,那我們看看這個(gè)的read操作圖示:
通過(guò)圖示可以很清楚得發(fā)現(xiàn)闷串,如果是AIO發(fā)起read操作之后,kernel收到請(qǐng)求后會(huì)立即響應(yīng)應(yīng)用進(jìn)程application筋量,所以應(yīng)用進(jìn)程完全可以做其他的事烹吵,不會(huì)造成任何的block。待kernel第一桨武、二階段都已經(jīng)完成之后肋拔,會(huì)給應(yīng)用進(jìn)程發(fā)送一個(gè)signal,告訴它read操作已經(jīng)完成呀酸。所以AIO的特點(diǎn)是在IO的兩個(gè)階段都不會(huì)發(fā)生阻塞凉蜂,而是全權(quán)交給系統(tǒng)內(nèi)核才完成,內(nèi)核完成后通過(guò)信號(hào)告知應(yīng)用進(jìn)程即可。
五窿吩、各種I/O對(duì)比
屬性\模型 | 阻塞BIO | 非阻塞NIO | 異步AIO |
---|---|---|---|
blocking | 阻塞并同步 | 非阻塞但同步 | 非阻塞并異步 |
線程數(shù)(server:client) | 1:1 | 1:N | 0:N |
復(fù)雜度 | 簡(jiǎn)單 | 較復(fù)雜 | 復(fù)雜 |
吞吐量 | 低 | 高 | 高 |
具體使用得依據(jù)業(yè)務(wù)的實(shí)際應(yīng)用場(chǎng)景和性能需求而定茎杂,如果客戶(hù)端很少,并發(fā)量不大纫雁,那么完全可以選擇BIO煌往,不過(guò)得加入線程池管理;相反要求并發(fā)較高的話(huà)轧邪,就應(yīng)該采用NIO框架了携冤。
六、簡(jiǎn)單總結(jié)
BIO闲勺、NIO、AIO概念認(rèn)知:
- Java BIO : 同步并阻塞扣猫,服務(wù)器實(shí)現(xiàn)模式為一個(gè)連接一個(gè)線程菜循,即客戶(hù)端有連接請(qǐng)求時(shí)服務(wù)器端就需要啟動(dòng)一個(gè)線程進(jìn)行處理,如果這個(gè)連接不做任何事情會(huì)造成不必要的線程開(kāi)銷(xiāo)申尤,當(dāng)然可以通過(guò)線程池機(jī)制改善癌幕。
- Java NIO : 同步非阻塞,服務(wù)器實(shí)現(xiàn)模式為一個(gè)請(qǐng)求一個(gè)線程昧穿,即客戶(hù)端發(fā)送的連接請(qǐng)求都會(huì)注冊(cè)到多路復(fù)用器上勺远,多路復(fù)用器輪詢(xún)到連接有I/O請(qǐng)求時(shí)才啟動(dòng)一個(gè)線程進(jìn)行處理。
- Java AIO(NIO.2) : 異步非阻塞时鸵,服務(wù)器實(shí)現(xiàn)模式為一個(gè)有效請(qǐng)求一個(gè)線程胶逢,客戶(hù)端的I/O請(qǐng)求都是由OS先完成了再通知服務(wù)器應(yīng)用去啟動(dòng)線程進(jìn)行處理。
BIO饰潜、NIO初坠、AIO適用場(chǎng)景分析:
- BIO方式適用于連接數(shù)目比較小且固定的架構(gòu),這種方式對(duì)服務(wù)器資源要求比較高彭雾,并發(fā)局限于應(yīng)用中碟刺,JDK1.4以前的唯一選擇,但程序直觀簡(jiǎn)單易理解薯酝。
- NIO方式適用于連接數(shù)目多且連接比較短(輕操作)的架構(gòu)半沽,比如聊天服務(wù)器,并發(fā)局限于應(yīng)用中吴菠,編程比較復(fù)雜者填,JDK1.4開(kāi)始支持。
- AIO方式使用于連接數(shù)目多且連接比較長(zhǎng)(重操作)的架構(gòu)做葵,比如相冊(cè)服務(wù)器幔托,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜,JDK7開(kāi)始支持重挑。