我是風(fēng)月連城,喜歡用簡(jiǎn)單的語(yǔ)言闡述知識(shí)點(diǎn)
長(zhǎng)期分享原創(chuàng)java文章,分享進(jìn)階架構(gòu)師學(xué)習(xí)筆記及學(xué)習(xí)資料
喜歡的可以點(diǎn)贊關(guān)注,共同學(xué)習(xí),一起進(jìn)步
0 ) 哈哈,其實(shí)我是個(gè)標(biāo)題黨,NIO不是牛逼IO,是非阻塞IO
NIO 也能算是一種思想,非阻塞IO通信思想,Netty就是基于NIO思想的NIO框架,
想花一分鐘知道Netty是什么的可以看看這么說(shuō)吧,Netty很簡(jiǎn)單,其實(shí)就是個(gè)Jar包,是作為通訊組件用的
什么是非阻塞?(為什么我沒(méi)有說(shuō)什么是IO,既然你都學(xué)到NIO了,,,要是不知道什么是IO的話我也沒(méi)辦法咯..)
這篇文章也是簡(jiǎn)單介紹NIO,想要看各類源碼的同學(xué)可以繞道了- -
1 ) 異步非阻塞例子:(網(wǎng)上看到的比較短小精悍的好例子,直接拿過(guò)來(lái)了)
老張愛(ài)喝茶,廢話不說(shuō),煮開(kāi)水。
出場(chǎng)人物:老張,水壺兩把(普通水壺,簡(jiǎn)稱水壺;會(huì)響的水壺,簡(jiǎn)稱響水壺)。
1 老張把水壺放到火上,原地不動(dòng)等水開(kāi)。(同步阻塞)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?---------->老張覺(jué)得自己有點(diǎn)傻
2 老張把水壺放到火上,去客廳看毛騙,時(shí)不時(shí)去看看水開(kāi)沒(méi)有。(同步非阻塞)?
?---------->老張覺(jué)得自己有點(diǎn)傻
于是變高端了,買了把會(huì)響笛的那種水壺。水開(kāi)之后,能大聲發(fā)出嘀~~~~的響聲。
3 老張把響水壺放到火上,立等水開(kāi)。(異步阻塞)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?--------->老張覺(jué)得自己有點(diǎn)傻
4 老張把響水壺放到火上,去客廳看毛騙,水壺響之前不再去看它,響了再去拿壺。(異步非阻塞)?
---------->嗯,老張覺(jué)得自己棒棒噠
2 ) 小結(jié):簡(jiǎn)單講,Java NIO的非阻塞模式就是,使一個(gè)線程從某通道發(fā)送請(qǐng)求讀取(或者寫入)數(shù)據(jù),(如燒水)
他不是保持線程阻塞,所以在讀取(或者寫入)數(shù)據(jù)前,該線程可以繼續(xù)做其他的事情。? ? ? (例如客廳看毛騙)
3 )? IO VS NIO 的比較? (不同之處)
1.IO只能實(shí)現(xiàn)阻塞式的網(wǎng)絡(luò)通信。NIO能夠?qū)崿F(xiàn)非阻塞的網(wǎng)絡(luò)通信.(廢話)
2.標(biāo)準(zhǔn)IO基于字節(jié)/字符流進(jìn)行操作;而NIO是基于通道(Channel)進(jìn)行操作的。(話說(shuō),通往女人心靈的通道是xxx道...)
3.流的讀寫通常是單向的,要么輸入,要么輸出,不能既是輸入流又是輸出流。通道是雙向的,既可以寫數(shù)據(jù)到通道,又可以從通道中讀取數(shù)據(jù);
4 ) 學(xué)習(xí)目標(biāo) : 雖然現(xiàn)在我們不會(huì)直接編寫NIO來(lái)完成我們的網(wǎng)絡(luò)層通訊,而是使用成熟的基于NIO的網(wǎng)絡(luò)框架來(lái)實(shí)現(xiàn)我們的網(wǎng)絡(luò)層。如,netty、mina。但對(duì)NIO網(wǎng)絡(luò)編程過(guò)程的了解,非常有助于我們更深入的理解netty、mina等網(wǎng)絡(luò)框架,以至于能更好的使用它們。有人問(wèn)了,不學(xué)這個(gè)對(duì)我敲代碼有何影響,可以說(shuō),毛影響都沒(méi).
5 ) 知道什么是NIO后,我們?cè)賮?lái)看看java NIO的三個(gè)重要組成部分:
Channel(通道),Buffer(緩沖區(qū)),Selector(選擇器)。
當(dāng)然,類比學(xué)習(xí)是比較好的學(xué)習(xí)方法,這里我仍然跟傳統(tǒng)IO做比較,希望他不要打我
6 ) Channel ( 通道 ),顧名思義,就是通向什么的道路,為某個(gè)提供了渠道。
1.傳統(tǒng)IO中,Stream是單向的,比如InputStream只能進(jìn)行讀取操作,OutputStream只能進(jìn)行寫操作。
而Channel是雙向的,既可用來(lái)進(jìn)行讀操作,又可用來(lái)進(jìn)行寫操作。
2.具體的常見(jiàn)實(shí)現(xiàn)通道有FileChannel,SocketChanel,ServerSocketChannel,DatagramChannel等
跟具體的實(shí)現(xiàn)流FileInputStream,FileOutputStream,FileReader,FileWriter,節(jié)點(diǎn)流包裝流緩沖流等等功能類似
7 ) Buffer(緩沖區(qū)),是NIO中非常重要的一個(gè)東西,實(shí)際上就是一個(gè)容器,是一個(gè)連續(xù)數(shù)組。在NIO中所有數(shù)據(jù)的讀和寫都離不開(kāi)Buffer。在NIO中,讀取的數(shù)據(jù)只能放在Buffer中。同樣地,寫入數(shù)據(jù)也是先寫入到Buffer中。
上面的圖描述了從一個(gè)客戶端向服務(wù)端發(fā)送數(shù)據(jù),然后服務(wù)端接收數(shù)據(jù)的過(guò)程。
簡(jiǎn)單的講就是,要想使用Channel(通道)傳遞數(shù)據(jù),必須先把數(shù)據(jù)丟進(jìn)Buffer(緩沖區(qū),容器)里.
在NIO中,Buffer是一個(gè)頂層父類,它是一個(gè)抽象類,常用的Buffer的子類有:
ByteBuffer,IntBuffer,CharBuffer,LongBuffer,DoubleBuffer,FloatBuffer,ShortBuffer等
8 ) Selector , 可以說(shuō)它是NIO中最關(guān)鍵的一個(gè)部分,Selector的作用就是用來(lái)輪詢每個(gè)注冊(cè)的Channel,一旦發(fā)現(xiàn)Channel有注冊(cè)的事件發(fā)生,便獲取事件然后進(jìn)行處理。
以前傳統(tǒng)socket編程時(shí),accept方法會(huì)一直阻塞,直到有客戶端請(qǐng)求的到來(lái),并返回socket進(jìn)行相應(yīng)的處理。整個(gè)過(guò)程是就像上面的例子那樣,直到水壺?zé)_(kāi)了(響應(yīng)回去了)才能去處理下一個(gè)請(qǐng)求.當(dāng)然我們也可以用線程池的模式.
NIO則為我們提供了更好的解決方案,Selector選擇器能夠檢測(cè)多個(gè)注冊(cè)的通道上是否有事件發(fā)生,如果有事件發(fā)生,便獲取事件然后針對(duì)每個(gè)事件進(jìn)行相應(yīng)的響應(yīng)處理。這樣一來(lái),只是用一個(gè)單線程就可以管理多個(gè)通道,也就是管理多個(gè)連接。這樣使得只有在連接真正有讀寫事件發(fā)生時(shí),才會(huì)調(diào)用函數(shù)來(lái)進(jìn)行讀寫,就大大地減少了系統(tǒng)開(kāi)銷,并且不必為每個(gè)連接都創(chuàng)建一個(gè)線程,不用去維護(hù)多個(gè)線程,并且避免了多線程之間的上下文切換導(dǎo)致的開(kāi)銷。并且是按順序處理,基于通道(Channel)和緩沖區(qū)(Buffer)來(lái)傳輸和保存數(shù)據(jù)。
與Selector有關(guān)的一個(gè)關(guān)鍵類是SelectionKey,一個(gè)SelectionKey表示一個(gè)到達(dá)的事件,這2個(gè)類構(gòu)成了服務(wù)端處理業(yè)務(wù)的關(guān)鍵邏輯。