同步和異步區(qū)別:有無(wú)通知(是否輪詢)
堵塞和非堵塞區(qū)別:操作結(jié)果是否等待(是否馬上有返回值)啦桌,只是設(shè)計(jì)方式的不同
1,同步和異步是針對(duì)應(yīng)用程序和內(nèi)核的交互而言的。
2,阻塞和非阻塞是針對(duì)于進(jìn)程在訪問(wèn)數(shù)據(jù)的時(shí)候哈蝇,根據(jù)IO操作的就緒狀態(tài)來(lái)采取的不同方式,說(shuō)白了是一種讀取或者寫入操作函數(shù)的實(shí)現(xiàn)方式攘已,阻塞方式下讀取或者寫入函數(shù)將一直等待炮赦,而非阻塞方式下,讀取或者寫入函數(shù)會(huì)立即返回一個(gè)狀態(tài)值样勃。
由上描述基本可以總結(jié)一句簡(jiǎn)短的話吠勘,同步和異步是目的,阻塞和非阻塞是實(shí)現(xiàn)方式峡眶。
1:同步指的是用戶進(jìn)程觸發(fā)IO操作并等待或者輪詢的去查看IO操作是否就緒. ? ??自己上街買衣服剧防,自己親自干這件事,別的事干不了辫樱。
2:異步異步是指用戶進(jìn)程觸發(fā)IO操作以后便開始做自己的事情峭拘,而當(dāng)IO操作已經(jīng)完成的時(shí)候會(huì)得到IO完成的通知(異步的特點(diǎn)就是通知) ? ?告訴朋友自己合適衣服的尺寸,大小狮暑,顏色鸡挠,讓朋友委托去賣,然后自己可以去干別的事搬男。(使用異步IO時(shí)拣展,Java將IO讀寫委托給OS處理,需要將數(shù)據(jù)緩沖區(qū)地址和大小傳給OS)
3:阻塞所謂阻塞方式的意思是指, 當(dāng)試圖對(duì)該文件描述符進(jìn)行讀寫時(shí), 如果當(dāng)時(shí)沒(méi)有東西可讀,或者暫時(shí)不可寫, 程序就進(jìn)入等待 狀態(tài), 直到有東西可讀或者可寫為止. ? ? 去公交站充值缔逛,發(fā)現(xiàn)這個(gè)時(shí)候备埃,充值員不在(可能上廁所去了),然后我們就在這里等待褐奴,一直等到充值員回來(lái)為止按脚。(當(dāng)然現(xiàn)實(shí)社會(huì),可不是這樣歉糜,但是在計(jì)算機(jī)里確實(shí)如此乘寒。)
4非阻塞狀態(tài)下, 如果沒(méi)有東西可讀, 或者不可寫, 讀寫函數(shù)馬上返回, 而不會(huì)等待,銀行里取款辦業(yè)務(wù)時(shí)匪补,領(lǐng)取一張小票伞辛,領(lǐng)取完后我們自己可以玩玩手機(jī)烂翰,或者與別人聊聊天,當(dāng)輪我們時(shí)蚤氏,銀行的喇叭會(huì)通知甘耿,這時(shí)候我們就可以去了。
同步阻塞IO(JAVA BIO):
同步并阻塞竿滨,服務(wù)器實(shí)現(xiàn)模式為一個(gè)連接一個(gè)線程佳恬,即客戶端有連接請(qǐng)求時(shí)服務(wù)器端就需要啟動(dòng)一個(gè)線程進(jìn)行處理,如果這個(gè)連接不做任何事情會(huì)造成不必要的線程開銷于游,當(dāng)然可以通過(guò)線程池機(jī)制改善毁葱。
同步非阻塞IO(Java NIO) :
NIO 有一個(gè)主要的類Selector,這個(gè)類似一個(gè)觀察者贰剥,只要我們把需要探知的socketchannel告訴Selector倾剿,我們接著做別的事情,當(dāng)有事件發(fā)生時(shí)蚌成,他會(huì)通知我們前痘,傳回一組SelectionKey,我們讀取這些Key担忧,就會(huì)獲得我們剛剛注冊(cè)過(guò)的socketchannel芹缔,然后,我們從這個(gè)Channel中讀取數(shù)據(jù)瓶盛,接著我們可以處理這些數(shù)據(jù)最欠。
?同步非阻塞,服務(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)行處理。用戶進(jìn)程也需要時(shí)不時(shí)的詢問(wèn)IO操作是否就緒帆锋,這就要求用戶進(jìn)程不停的去詢問(wè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)然可以通過(guò)線程池機(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) :在此種模式下馍佑,用戶進(jìn)程只需要發(fā)起一個(gè)IO操作然后立即返回,等IO操作真正的完成以后梨水,應(yīng)用程序會(huì)得到IO操作完成的通知拭荤,此時(shí)用戶進(jìn)程只需要對(duì)數(shù)據(jù)進(jìn)行處理就好了,不需要進(jìn)行實(shí)際的IO讀寫操作疫诽,因?yàn)檎嬲腎O讀取或者寫入操作已經(jīng)由內(nèi)核完成了舅世。
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開始支持翎碑。
AIO方式使用于連接數(shù)目多且連接比較長(zhǎng)(重操作)的架構(gòu),比如相冊(cè)服務(wù)器之斯,充分調(diào)用OS參與并發(fā)操作日杈,編程比較復(fù)雜,JDK7開始支持佑刷。
Recotor
反應(yīng)器(Reactor)模式是為了處理一個(gè)或多個(gè)客戶端同時(shí)提交的服務(wù)請(qǐng)求而設(shè)計(jì)的莉擒。事件驅(qū)動(dòng)的應(yīng)用程序可以使用反應(yīng)器結(jié)構(gòu)化模式,多路分解并分配從一個(gè)或多個(gè)客戶端發(fā)給應(yīng)用程序的服務(wù)請(qǐng)求。該模式的別名有:分配器(Dispatcher)瘫絮,通知器(Notifier)
以下例子摘自:http://daimojingdeyu.iteye.com/blog/828696
先用比較直觀的方式來(lái)介紹一下這種方式的優(yōu)點(diǎn)涨冀,通過(guò)和常用的多線程方式比較一下,可能更好理解麦萤。
以去飯店吃飯為例鹿鳖,每一伙人來(lái)就餐就是一個(gè)事件,吃飯的人會(huì)先看一下菜單壮莹,然后點(diǎn)菜翅帜。處理這些就餐事件的就需要我們的服務(wù)人員了。每個(gè)服務(wù)員相當(dāng)于一個(gè)線程命满。
多線程處理的方式會(huì)是這樣的:
一個(gè)人來(lái)就餐涝滴,一個(gè)服務(wù)員去服務(wù),然后客人會(huì)看菜單,點(diǎn)菜歼疮。 服務(wù)員將菜單給后廚杂抽。
二個(gè)人來(lái)就餐,二個(gè)服務(wù)員去服務(wù)……
五個(gè)人來(lái)就餐腋妙,五個(gè)服務(wù)員去服務(wù)……
這個(gè)就是多線程的處理方式默怨,一個(gè)事件到來(lái),就會(huì)有一個(gè)線程服務(wù)骤素。很顯然這種方式在人少的情況下會(huì)有很好的用戶體驗(yàn)匙睹,每個(gè)客人都感覺(jué)自己是VIP,專人服務(wù)的济竹。如果飯店一直這樣同一時(shí)間最多來(lái)5個(gè)客人痕檬,這家飯店是可以很好的服務(wù)下去的。
來(lái)了一個(gè)好消息送浊,因?yàn)檫@家店的服務(wù)好梦谜,吃飯的人多了起來(lái)。同一時(shí)間會(huì)來(lái)10個(gè)客人袭景,老板很開心唁桩,但是只有5個(gè)服務(wù)員,這樣就不能一對(duì)一服務(wù)了耸棒,有些客人就要沒(méi)有人管了荒澡。老板就又請(qǐng)了5個(gè)服務(wù)員,現(xiàn)在好了与殃,又能每個(gè)人都受VIP待遇了单山。
越來(lái)越多的人對(duì)這家飯店滿意,客源又多了幅疼,同時(shí)來(lái)吃飯的人到了20人米奸,老板高興不起來(lái)了,再請(qǐng)服務(wù)員吧爽篷,占地方不說(shuō)悴晰,還要開工錢,再請(qǐng)人就攢不到錢了狼忱。怎么辦呢膨疏?老板想了想,10個(gè)服務(wù)員對(duì)付20個(gè)客人也是能對(duì)付過(guò)來(lái)的钻弄,服務(wù)員勤快點(diǎn)就好了,伺候完一個(gè)客人馬上伺候另外一個(gè)者吁,還是來(lái)得及的窘俺。綜合考慮了一下,老板決定就使用10個(gè)服務(wù)人員的線程池啦~~~
但是這樣有一個(gè)比較嚴(yán)重的缺點(diǎn)就是,如果正在接受服務(wù)員服務(wù)的客人點(diǎn)菜很慢瘤泪,其他的客人可能就要等好長(zhǎng)時(shí)間了灶泵。有些火爆脾氣的客人可能就等不了走人了。
Reactor就可以很好的解決這個(gè)問(wèn)題对途。
因?yàn)辄c(diǎn)菜才通常是很耗時(shí)的赦邻,所以當(dāng)有人來(lái)吃飯的時(shí)候,可以先把菜單交給點(diǎn)菜的人自己瀏覽实檀,等點(diǎn)菜的人想好了要點(diǎn)的菜的時(shí)候再招呼服務(wù)員惶洲,等服務(wù)員過(guò)來(lái)了之后就可以為顧客點(diǎn)菜并發(fā)送到后廚了。這個(gè)在某種意義上說(shuō)就是用單線程在做多線程的事情膳犹。
Reactor的事件驅(qū)動(dòng)就體現(xiàn)在了只有當(dāng)事件發(fā)生(客戶招呼服務(wù)員點(diǎn)菜)的時(shí)候恬吕,服務(wù)員(線程)才去處理。而客戶剛進(jìn)入飯店的時(shí)候须床,是不需要去處理的铐料。
從這個(gè)簡(jiǎn)單的例子應(yīng)該可以基本明白R(shí)eactor是干什么的了吧。(由事件觸發(fā)豺旬,并分發(fā)請(qǐng)求)
2.2Reactor模式的思想:分而治之+事件驅(qū)動(dòng)
分而治之:
一個(gè)connection里發(fā)生的完整的網(wǎng)絡(luò)處理過(guò)程一般分為accept钠惩、read、decode族阅、compute篓跛、encode、send這幾步耘分。Reactor將每個(gè)步驟映射為一個(gè)task举塔,服務(wù)端端的線程執(zhí)行的最小邏輯單元不再是一次完整的網(wǎng)絡(luò)處理過(guò)程,而是更小的task求泰,且采用非阻塞的執(zhí)行方式央渣;
事件驅(qū)動(dòng):
每個(gè)task對(duì)應(yīng)一個(gè)特定的事件,當(dāng)task準(zhǔn)備就緒時(shí)渴频,對(duì)應(yīng)的事件通知就會(huì)發(fā)出芽丹。Reactor收到事件后,分發(fā)給綁定了對(duì)應(yīng)事件的Handler執(zhí)行task卜朗。
Reactor:負(fù)責(zé)響應(yīng)事件拔第,分發(fā)給綁定了該事件的handler執(zhí)行task
Handler:綁定了某類事件,負(fù)責(zé)執(zhí)行該事件對(duì)應(yīng)的task场钉。
Acceptor:Handler的一種蚊俺,綁定了connect事件。它在系統(tǒng)啟動(dòng)的時(shí)候就已經(jīng)綁定了connnect事件逛万,并注冊(cè)到reactor中泳猬。當(dāng)有客戶端發(fā)起connect請(qǐng)求時(shí),reactor會(huì)收到accept事件,然后分發(fā)給acceptor得封。acceptor首先會(huì)accept新的連接埋心,然后新建一個(gè)handler,將其與該連接上得read事件綁定忙上,并注冊(cè)到reactor中拷呆。