七 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里拿出来的

思考:那么咱们想要执行一些耗时的操做时,应该本身管理一个线程池,仍是用上面的这两个方法拿到线程呢?

相关文章
相关标签/搜索