Netty 源码解析(五): Netty 的线程池分析

在这里插入图片描述

今天是猿灯塔“365篇原创计划”第五篇。 接下来的时间灯塔君持续更新Netty系列一共九篇

Netty 源码解析(一): 开始

Netty 源码解析(二): Netty 的 Channel

Netty 源码解析(三): Netty的 Future 和 Promise

Netty 源码解析(四): Netty 的 ChannelPipeline

当前:Netty 源码解析(五): Netty 的线程池分析

Netty 源码解析(六): Channel 的 register 操作

Netty 源码解析(七): NioEventLoop 工作流程

Netty 源码解析(八): 回到 Channel 的 register 操作

Netty 源码解析(九): connect 过程和 bind 过程分析

今天呢!灯塔君跟大家讲:

Netty 的线程池分析

Netty 中的线程池 EventLoopGroup
接下来,我们来分析 Netty 中的线程池。Netty 中的线程池比较不好理解,因为它的类比较多,而且它们之间的关系错综复杂。看下图,感受下 NioEventLoop 类和 NioEventLoopGroup 类的继承结构:

在这里插入图片描述

这张图我按照继承关系整理而来,大家仔细看一下就会发现,涉及到的类确实挺多的。本节来给大家理理清楚这部分内容。

首先,我们说的 Netty 的线程池,指的就是 NioEventLoopGroup 的实例;线程池中的单个线程,指的是右边 NioEventLoop 的实例。

回顾下我们第一节介绍的 Echo 例子,客户端和服务端的启动代码中,最开始我们总是先实例化 NioEventLoopGroup:

// EchoClient 代码最开始:
EventLoopGroup group = new NioEventLoopGroup();

// EchoServer 代码最开始:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

下面,我们就从 NioEventLoopGroup 的源码开始进行分析。

我们打开 NioEventLoopGroup 的源码,可以看到,NioEventLoopGroup 有多个构造方法用于参数设置,最简单地,我们采用无参构造函数,或仅仅设置线程数量就可以了,其他的参数采用默认值。

比如上面的代码中,我们只在实例化 bossGroup 的时候指定了参数,代表该线程池需要一个线程。

public NioEventLoopGroup() {
   
    this(0);
}
public NioEventLoopGroup(int nThreads) {
   
    this(nThreads, (Executor) null);
}

...
  
// 参数最全的构造方法
public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                         final SelectorProvider selectorProvider,
                         final SelectStrategyFactory selectStrategyFactory,
                         final RejectedExecutionHandler rejectedExecutionHandler) {
   
    // 调用父类的构造方法
    super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler);
}

我们来稍微看一下构造方法中的各个参数:

  • nThreads:这个最简单,就是线程池中的线程数,也就是 NioEventLoop 的实例数量。
  • executor:我们知道,我们本身就是要构造一个线程池(Executor),为什么这里传一个 executor 实例呢?它其实不是给线程池用的,而是给 NioEventLoop 用的,以后再说。
  • chooserFactory:当我们提交一个任务到线程池的时候,线程池需要选择(choose)其中的一个线程来执行这个任务,这个就是用来实现选择策略的。
  • selectorProvider:这个简单,我们需要通过它来实例化 JDK 的 Selector,可以看到每个线程池都持有一个 selectorProvider 实例。
  • selectStrategyFactory:这个涉及到的是线程池中线程的工作流程,在介绍 NioEventLoop 的时候会说。
  • rejectedExecutionHandler:这个也是线程池的好朋友了,用于处理线程池中没有可用的线程来执行任务的情况。在 Netty 中稍微有一点点不一样,这个是给 NioEventLoop 实例用的,以后我们再详细介绍。

这里介绍这些参数是希望大家有个印象而已,大家发现没有,在构造 NioEventLoopGroup 实例时的好几个参数,都是用来构造 NioEventLoop 用的。

下面,我们从 NioEventLoopGroup 的无参构造方法开始,跟着源码走:

public NioEventLoopGroup() {
   
    this(0);
}

然后一步步走下去,到这个构造方法:

public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) {
   
    
    super(nThreads, threadFactory, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}

大家自己要去跟一下源码,这样才知道中间设置了哪些默认值,下面这几个参数都被设置了默认值:

  • selectorProvider = SelectorProvider.provider()

    这个没什么好说的,调用了 JDK 提供的方法

  • selectStrategyFactory = DefaultSelectStrategyFactory.INSTANCE

    这个涉及到的是线程在做 select 操作和执行任务过程中的策略选择问题,在介绍 NioEventLoop 的时候会用到。

  • rejectedExecutionHandler = RejectedExecutionHandlers.reject()

    大家进去看一下 reject() 方法,也就是说,Netty 选择的默认拒绝策略是:抛出异常

跟着源码走,我们会来到父类 MultithreadEventLoopGroup 的构造方法中:

protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
   
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
}

这里我们发现,如果采用无参构造函数,那么到这里的时候,默认地 nThreads 会被设置为 *CPU 核心数 2。大家可以看下 DEFAULT_EVENT_LOOP_THREADS 的默认值,以及 static 代码块的设值逻辑。

我们继续往下走:

protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值