新聞中心
NIO編程一直是Java知識體系中的一個重點(diǎn)。前幾年的時(shí)間面試的門檻是了解NIO,現(xiàn)在就不一樣了,最起碼也要精通NIO,因此學(xué)習(xí)javaNIO編程是非常有必要的。這篇文章就開始對NIO進(jìn)行一個認(rèn)識。本文參考了慕課網(wǎng),特在此說明。

一、認(rèn)識NIO
1、什么是BIO?
想要學(xué)習(xí)NIO,那我們就必須先要認(rèn)識一下BIO,在JDK1,4之前,我們使用網(wǎng)絡(luò)連接的時(shí)候一直都是使用的BIO,也就是阻塞式,網(wǎng)絡(luò)模型是下面這個樣子的。
上面這個網(wǎng)絡(luò)模型是這樣的。
(1)server創(chuàng)建初始化一些預(yù)備工作之后,就開始等待客戶端client的鏈接
(2)client開始鏈接server。
(3)server一旦請求到client的請求之后就會開啟一個線程去處理。
就好比是只有一家餐飲店,每進(jìn)來一個顧客,我們就需要去創(chuàng)建一個線程去處理。這就是BIO。他的缺點(diǎn)可想而知。如果客戶端很多的話,server就必須要開啟很多個Thread去處理,這樣也太麻煩了。畢竟像淘寶微信這樣的平臺好幾億人再用,而且請求量這么大,總不能開啟幾億個線程去處理吧。這時(shí)候在jdk1.4就出現(xiàn)了NIO。
2、出現(xiàn)了NIO
既然BIO有這么多的缺點(diǎn),java官方肯定也明白,于是在jdk1.4的時(shí)候及時(shí)的加入了NIO。
這個跟上一個的區(qū)別我們來捋一下:
(1)一個客戶端進(jìn)來之后首先加入到Set中
(2)server時(shí)刻輪詢著這個set,一旦發(fā)現(xiàn)有客戶端連接進(jìn)來就開始handler
(3)多個client連接進(jìn)來的時(shí)候,都保存在這個set中,這樣我們就可以輪詢處理多個client了。
這就NIO,他的優(yōu)點(diǎn)從上面的圖也可以看出來。我們可能只需要創(chuàng)建一個Thread就可以處理所有的client了。當(dāng)然每一個client要做的事情不一樣,有的是連接請求,有的是讀寫請求,這時(shí)候server就可以根據(jù)不同的請求使用不同的handler了。再給出一張圖看一下:
當(dāng)然,這只是列舉出了NIO的特點(diǎn),還有大致網(wǎng)絡(luò)模型,想要去真正的了解他,還是代碼來的直接。
二、代碼實(shí)現(xiàn)
1、基本概念
在正式開始代碼的編寫之前,我們還要先認(rèn)識一下涉及到的幾個類。
(1)channel
它相當(dāng)于是一個通道,這個通道是流通數(shù)據(jù)的,我們既可以從通道中讀取數(shù)據(jù),又可以寫數(shù)據(jù)到通道。常見的channel有四個:FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel。
FileChannel 從文件中讀寫數(shù)據(jù)。
DatagramChannel 能通過UDP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)。
SocketChannel 能通過TCP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)。
ServerSocketChannel可以監(jiān)聽新進(jìn)來的TCP連接,像Web服務(wù)器那樣。對每一個新進(jìn)來的連接都會創(chuàng)建一個SocketChannel。
(2)Buffer
Buffer用于和通道進(jìn)行交互。數(shù)據(jù)是從通道讀入緩沖區(qū),從緩沖區(qū)寫入到通道中的。
使用Buffer讀寫數(shù)據(jù)一般遵循以下四個步驟:
- 寫入數(shù)據(jù)到Buffer
- 調(diào)用flip()方法
- 從Buffer中讀取數(shù)據(jù)
- 調(diào)用clear()方法或者compact()方法
(3)Selector
Selector(選擇器)能夠檢測一到多個NIO通道,并能夠知曉通道是否為諸如讀寫事件做好準(zhǔn)備的組件。這樣,一個單獨(dú)的線程可以管理多個channel,從而管理多個網(wǎng)絡(luò)連接。
2、實(shí)現(xiàn)步驟
我們在這里實(shí)現(xiàn)一個類似于聊天室的案例,上面已經(jīng)把NIO涉及到的一些核心類說了一下,下面說一下實(shí)現(xiàn)的步驟。這個步驟是要結(jié)合上面的圖來理解會比較容易一些:
第一步:創(chuàng)建Selector
第二步:創(chuàng)建ServerSocketChannel,綁定監(jiān)聽端口
第三步:將Channel設(shè)置為非阻塞模式
第四步:將Channel注冊到Selector上,監(jiān)聽連接事件
第五步:循環(huán)調(diào)用Selector的select方法,檢測就緒情況
第六步:調(diào)用selectedKeys方法獲取就緒channel集合
第七步:判斷就緒事件種類,調(diào)用業(yè)務(wù)處理方法
第八步:根據(jù)業(yè)務(wù)需要決定是否再次注冊監(jiān)聽事件,重復(fù)執(zhí)行第三步操作
有了這個步驟我們再去代碼實(shí)現(xiàn)。
3、代碼實(shí)現(xiàn)
(1)server端代碼開發(fā)
首先我們看一下服務(wù)器端
上面把server中基本的是步驟實(shí)現(xiàn)了?,F(xiàn)在開始真正的去處理一下。
第一種情況:鏈接事件處理
第二種情況:讀寫時(shí)間處理
到了第五步broadCast方法其實(shí)我們可以對此進(jìn)行一個變化,在這里我們實(shí)現(xiàn)的是廣播到其他所有client。但是如果是一對一聊天的話我們就可以單播到指定client。
這就是整個服務(wù)器端的開發(fā),當(dāng)然還要客戶端的開發(fā),我們同樣來看看。
(2)client端代碼開發(fā)
客戶端代碼說實(shí)話就比較輕松一點(diǎn)了。
我們就再來看看,客戶端如何處理服務(wù)器端返回的數(shù)據(jù)。
readHandler方法是如何讀取呢?
到這一步,整個客戶端的代碼就算是完成了,如果你仔細(xì)的捋一遍,其實(shí)整個流程還是很清晰的。
三、總結(jié)
雖然NIO這么好其實(shí)還是有很多缺點(diǎn)的,在上面的代碼量其實(shí)你就可以發(fā)現(xiàn)了,大量的代碼使得我們在構(gòu)建復(fù)雜系統(tǒng)的時(shí)候超級麻煩,有時(shí)候正是這些技術(shù)的不完備,才造成了我們程序員工作量大,壓力大,但是科技的進(jìn)步畢竟是要一點(diǎn)一點(diǎn)發(fā)展的嘛。另外說一句這個NIO還有一個大坑,就是Selector空輪詢的時(shí)候,導(dǎo)師CPU100%。不過這種情況我還沒試過。
想要精通NIO的話,這篇文章真的遠(yuǎn)遠(yuǎn)不夠,頂多算是入門把。想要真正認(rèn)識我覺得首先要深入源碼,然后就是實(shí)際場景中的使用,不過目前來看的話netty和mina框架要比java的NIO好的多,不單單是性能,更重要的是我們的開發(fā)效率。算是在一定程度上避免了我們程序員“錢多話少死得快”的現(xiàn)象了吧。
網(wǎng)站標(biāo)題:這篇Java的NIO編程,保證你能看懂
網(wǎng)站地址:http://www.dlmjj.cn/article/djssscd.html


咨詢
建站咨詢
