七 netty學習之 boss線程池,worker線程的生命週期

netty的線程模型數據庫

1. bossGroup線程組

若是綁定了一個端口的話,那麼只有一條線程來處理全部到來的請求.即便這個線程組裏可能不止一條線程 若是綁定了兩個端口的話,那就有兩條線程 new EventLoopGroup(1) 因此, 能夠指定線程組之初始化1條線程服務器

因此, ServerBootstrap監聽一個端口對應一個boss線程,它們一一對應.網絡

2. worker線程組

在boss接受了socket鏈接請求後,會產生一個channel,並把這個channel交給ServerBootstrap初始化時指定的ServerSocketChannelFactory處理, boss線程則繼續處理socket的請求

ServerSocketChannelFactory則會到worker線程池中找出一條worker線程來繼續處理這個請求框架

**若是是OioServerSocketChannelFactory,**那麼這個channel上全部的socket消息,從開始到channel(socket)關閉,都只由這個特定的worker線程來處理,也就是說打開的一個socket對應一個指定的worker線程,在這個socket沒有關閉的狀況,只能爲這個socket處理消息,沒有辦法爲其餘socket服務jvm

** 若是是NioServerSocketChannelFactory,** 則否則.每一個worker能夠服務不一樣的socket或者channel,也就是說,channel和worker再也不是一一對應的關係.socket

** 總結上面,NioServerSocketChannelFactory 只須要少許活動的worker線程,就能處理好衆多的 channel,而OioServerSocketChannelFactory 必需要是打開和channel等量的worker線程來服務.**oop

線程是一種資源,因此netty服務器須要處理長鏈接的時候,最好選擇NioServerSocketChannelFactory,這樣能夠避免建立大量的worker線程. 在用做http服務器的時候,最好也選擇NioServerSocketChannelFactory,

3. worker線程的生命週期

** inBound的handler 和 outBound的handler是否是在一個線程裏? 爲何我測試的可能在一個線程,也可能不在一個線程 ** 下面這段話來源於網絡,彷佛和我測試的不符.測試

對 於Nio當messageReceived()方法執行後,若是沒有產生異常,worker線程就執行完畢了,它會被線程池回收。業務邏輯hanlder 會經過一些方法,把返回的數據交給指定好順序的DownStreamHandler處理,處理後的數據若是須要,會被寫入channel,進而經過綁定的 socket發送給客戶端。這個過程是由另一個線程池中的worker線程來完成的。this

4.減小worker線程的處理佔用時間

worker線程是由netty內部管理, 統一調配的一種資源,因此最好應該儘快的讓worker線程執行完畢,返回給線程池回收利用..net

** worker線程的大部分時間都消耗在ChannelPipeline的的各類handler中, 而在這些handler中,通常是負責應用程序邏輯滲入的那個handler最耗時間,他一般是排在最後的handler.因此把這部分處理內容交給另一個線程來處理,能夠有效的減小worker線程的週期循環時間. **

通常有兩種方法:
  1. new Thread().start(), 而worker線程執行完messageReceived 就結束了
  2. 利用 netty框架自帶的ExecutionHandler
public class DatabaseGatewayPipelineFactory implements ChannelPipelineFactory {  
  
    private final ExecutionHandler executionHandler;  
  
    public DatabaseGatewayPipelineFactory(ExecutionHandler executionHandler) {  
        this.executionHandler = executionHandler;  
    }  
  
    public ChannelPipeline getPipeline() {  
        return Channels.pipeline(  
                new DatabaseGatewayProtocolEncoder(),  
                new DatabaseGatewayProtocolDecoder(),  
                executionHandler, // 多個pipeline之間必須共享同一個ExecutionHandler  
                new DatabaseQueryingHandler());//業務邏輯handler,IO密集  
    }  
}

把 共享的ExecutionHandler實例放在業務邏輯handler以前便可,注意ExecutionHandler必定要在不一樣的pipeline 之間共享。它的做用是自動從ExecutionHandler本身管理的一個線程池中拿出一個線程來處理排在它後面的業務邏輯handler。而 worker線程在通過ExecutionHandler後就結束了,它會被ChannelFactory的worker線程池所回收。

它的構造方法是ExecutionHandler(Executor executor) ,很顯然executor就是ExecutionHandler內部管理的線程池了。netty額外給咱們提供了兩種線程池: MemoryAwareThreadPoolExecutor和OrderedMemoryAwareThreadPoolExecutor,它們都在org.jboss.netty.handler.execution 包下。 MemoryAwareThreadPoolExecutor 確保jvm不會由於過多的線程而致使內存溢出錯誤,OrderedMemoryAwareThreadPoolExecutor是前一個線程池的子類,除 了保證沒有內存溢出以外,還能夠保證channel event的處理次序

上面的ExecutionHandler彷佛在Netty5.0裏廢除了 OrderedMemoryAwareThreadPoolExecutor 和 MemoryAwareThreadPoolExecutor 也被廢除了

注意:

執行整個鏈是串行的, 若是業務邏輯比較耗時, 好比讀取數據庫,會致使worker線程被長期佔用而得不到釋放,最終影響的是整個服務器端的處理效率,因此,咱們把最後那個處理業務邏輯的handler放一個線程池裏執行,讓worker即便釋放.

ctx.executor().schedule

ctx.channel().eventLoop().schedule

上面兩個線程都是從workerGroup裏拿出來的

思考:那麼咱們想要執行一些耗時的操做時,應該本身管理一個線程池,仍是用上面的這兩個方法拿到線程呢?

相關文章
相關標籤/搜索