首頁技術(shù)文章正文

Java開發(fā)中Netty線程模型的原理是什么?

更新時間:2021-05-25 來源:黑馬程序員 瀏覽量:

Java開發(fā)中Netty線程模型原理解析,Netty是Java領(lǐng)域有名的開源網(wǎng)絡(luò)庫具有高性能和高擴(kuò)展性的特點(diǎn),很多流行的框架都是基于它來構(gòu)建。Netty 線程模型不是一成不變的,取決于用戶的啟動參數(shù)配置。通過設(shè)置不同的啟動參數(shù)Netty ,可同時支持 Reactor 單線程模型、多線程模型。

Netty線程模型就是Reactor模式的實(shí)現(xiàn),如圖:

Netty線程模型

Netty抽象了兩組線程池BossGroup和WorkerGroup,其類型都是NioEventLoopGroup,BossGroup用來接受客戶端發(fā)來的連接WorkerGroup則負(fù)責(zé)對完成TCP三次握手的連接進(jìn)行處理。

NioEventLoopGroup里面包含了多個NioEventLoop管理NioEventLoop的生命周期。每個NioEventLoop中包含了一個NIO Selector、一個隊列、一個線程;其中線程用來做輪詢注冊到Selector上的Channel的讀寫事件和對投遞到隊列里面的事件進(jìn)行處理。


Boss NioEventLoop線程的執(zhí)行步驟:

(1)處理accept事件與client建立連接, 生成NioSocketChannel。

(2)將NioSocketChannel注冊到某個worker NIOEventLoop上的selector

(3)處理任務(wù)隊列的任務(wù) 即runAllTasks。


Worker NioEventLoop線程的執(zhí)行步驟:

(1)輪詢注冊到自己Selector上的所有NioSocketChannel的read和write事件。

(2)2處理read和write事件在對應(yīng)NioSocketChannel處理業(yè)務(wù)。

(3)#runAllTasks處理任務(wù)隊列TaskQueue的任務(wù),一些耗時的業(yè)務(wù)處理可以放入TaskQueue中慢慢處理這樣不影響數(shù)據(jù)在pipeline中的流動處理。

Worker NIOEventLoop處理NioSocketChannel業(yè)務(wù)時,使用了pipeline (管道),管道中維護(hù)了handler處理器鏈表用來處理channel中的數(shù)據(jù)。

ChannelPipeline

Netty將Channel的數(shù)據(jù)管道抽象為ChannelPipeline,消息在ChannelPipline中流動和傳遞。ChannelPipeline持有I/O事件攔截器ChannelHandler的雙向鏈表,由ChannelHandler對I/O事件進(jìn)行攔截和處理,可以方便的新增和刪除ChannelHandler來實(shí)現(xiàn)不同的業(yè)務(wù)邏輯定制不需要對已有的ChannelHandler進(jìn)行修改能夠?qū)崿F(xiàn)對修改封閉和對擴(kuò)展的支持。


ChannelPipeline是一系列的ChannelHandler實(shí)例,流經(jīng)一個Channel的入站和出站事件可以被ChannelPipeline 攔截。每當(dāng)一個新的Channel被創(chuàng)建了,都會建立一個新的ChannelPipeline并綁定到該Channel上,這個關(guān)聯(lián)是永久性的;Channel既不能附上另一個ChannelPipeline也不能分離當(dāng)前這個。這些都由Netty負(fù)責(zé)完成,而無需開發(fā)人員的特別處理。


根據(jù)起源一個事件將由ChannelInboundHandler或ChannelOutboundHandler處理,ChannelHandlerContext實(shí)現(xiàn)轉(zhuǎn)發(fā)或傳播到下一個ChannelHandler。一個ChannelHandler處理程序可以通知ChannelPipeline中的下一個ChannelHandler執(zhí)行。Read事件(入站事件)和write事件(出站事件)使用相同的pipeline,入站事件會從鏈表head 往后傳遞到最后一個入站的handler出站事件會從鏈表tail往前傳遞到最前一個出站的 handler,兩種類型的 handler 互不干擾。

Netty線程模型

ChannelInboundHandler回調(diào)方法:

Netty線程模型

ChannelInboundHandler回調(diào)方法

Netty線程模型


異步非阻塞

寫操作:通過NioSocketChannel的write方法向連接里面寫入數(shù)據(jù)時候是非阻塞的,馬上會返回即使調(diào)用寫入的線程是我們的業(yè)務(wù)線程。Netty通過在ChannelPipeline中判斷調(diào)用NioSocketChannel的write的調(diào)用線程是不是其對應(yīng)的NioEventLoop中的線程,如果發(fā)現(xiàn)不是則會把寫入請求封裝為WriteTask投遞到其對應(yīng)的NioEventLoop中的隊列里面,然后等其對應(yīng)的NioEventLoop中的線程輪詢讀寫事件時候,將其從隊列里面取出來執(zhí)行。


讀操作:當(dāng)從NioSocketChannel中讀取數(shù)據(jù)時候并不是需要業(yè)務(wù)線程阻塞等待,而是等NioEventLoop中的IO輪詢線程發(fā)現(xiàn)Selector上有數(shù)據(jù)就緒時,通過事件通知方式來通知業(yè)務(wù)數(shù)據(jù)已就緒,可以來讀取并處理了。


每個NioSocketChannel對應(yīng)的讀寫事件都是在其對應(yīng)的NioEventLoop管理的單線程內(nèi)執(zhí)行,對同一個NioSocketChannel不存在并發(fā)讀寫,所以無需加鎖處理。


使用Netty框架進(jìn)行網(wǎng)絡(luò)通信時,當(dāng)我們發(fā)起I/O請求后會馬上返回,而不會阻塞我們的業(yè)務(wù)調(diào)用線程;如果想要獲取請求的響應(yīng)結(jié)果,也不需要業(yè)務(wù)調(diào)用線程使用阻塞的方式來等待,而是當(dāng)響應(yīng)結(jié)果出來的時候,使用I/O線程異步通知業(yè)務(wù)的方式,所以在整個請求 -> 響應(yīng)過程中業(yè)務(wù)線程不會由于阻塞等待而不能干其他事情。








猜你喜歡:

Java線程的生命周期及各種狀態(tài)轉(zhuǎn)換詳解

Netty快速入門教程[java培訓(xùn)]

Java中如何創(chuàng)建線程?【Java面試題】

黑馬程序員Java培訓(xùn)培訓(xùn)

分享到:
在線咨詢 我要報名
和我們在線交談!