ITPub博客

首页 > IT职业 > IT生活 > Netty源码-Reactor线程模型之NioEventLoopGro

Netty源码-Reactor线程模型之NioEventLoopGro

IT生活 作者:snoopyzjs 时间:2021-09-09 08:52:28 0 删除 编辑

Netty源码-Reactor线程模型之NioEventLoopGroup研究

在Netty网络编程中,不管是编写客户端代码,还是编写服务端代码,我们都写过这段代码

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

在Netty的线程模型中,NioEventLoopGroup扮演着线程池角色,一说到线程池,不由自主地地会想到ThreadPoolExecutor,NioEventLoopGroup是不是对ThreadPoolExecutor的二次封装了下,我们从下面几个方向来分析。

图片描述

NioEventLoopGroup源码分析思维导图

初始化时做了什么?

图片描述

NioEventLoopGroup层次结构图

从层次结构图上可以看出,NioEventLoopGroup实现了线程池模型的ScheduledExecutorService,ExecutorService和Executor接口,因此可知NioEventLoopGroup提供了线程池相关功能。

NioEventLoopGroup继承了MultithreadEventLoopGroup,父类MultithreadEventLoopGroup继承了抽象类
MultithreadEventExecutorGroup,其抽象方法newChild由子类实现,使用了模板设计模式,一步一步跟踪,最终定位到
MultithreadEventExecutorGroup的构造函数,初始化时做了3件事:

  • 创建线程工厂并构建线程执行器Executor

  • 创建指定数量nThreads的children线程组并初始化

  • 创建线程选择器chooser

创建线程工厂并构建线程执行器Executor:如果我们没有传executor,会帮忙创建一个线程工厂DefaultThreadFactory来构建线程执行器ThreadPerTaskExecutor。DefaultThreadFactory会创建FastThreadLocalThread线程来执行任务。

if (executor == null) {
  executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}

创建指定数量nThreads的children线程组并初始化:第一步创建指定数量nThreads的线程组。nThreads没有传或者传0,会默认指定2*cpu线程数。

protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {  //nThreads为0时,会设置2*cpu线程数
  super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}static {  //默认线程数:2*cpu
  DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(    "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));  if (logger.isDebugEnabled()) {
    logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
  }
}

第二步通过newChild()方法初始化children线程组,newChild()是个抽象方法,具体实现由子类NioEventLoopGroup完成。在newChild()方法中,NioEventLoop的初始化参数有6个:

  • 参数parent:NioEventLoopGroup线程组本身;

  • 参数executor:线程执行器,用于启动线程,在SingleThreadEventExecutor的doStartThread()方法中被调用;

  • 参数selectorProvider:NIO的Selector选择器的提供者;

  • 参数strategy:主要在NioEventLoop的run()方法中用于控制选择循环;

  • 参数rejectedExecutionHandler:非I/O任务提交被拒绝时的处理Handler;

  • 参数queueFactory:队列工厂,在NioEventLoop中,队列读是单线程操作,而队列写则可能是多线程操作,使用支持多生产者、单消费者的队列比较合适,默认为MpscChunkedArrayQueue队列。

//指定数量nThreads的children线程组children = new EventExecutor[nThreads];for (int i = 0; i 

创建线程选择器chooser:默认用的是
DefaultEventExecutorChooserFactory.INSTANCE,根据children线程组数量决定使用不同的选择器,使用了单例模式和工厂模式。

chooser = chooserFactory.newChooser(children);

与Java线程池的区别?

  • java线程池的队列是所有线程共享的,NioEventLoopGroup线程组的队列是每个线程独享的。

  • NioEventLoopGroup线程组没有最大线程数的概念。

  • NioEventLoopGroup线程组有线程选择器chooser的概念。

图片描述

NioEventLoopGroup线程组图

用到了哪些设计模式

  • 模板方法模式:MultithreadEventExecutorGroup类中抽象方法newChild()

  • 工厂模式:DefaultSelectStrategyFactory,DefaultEventExecutorChooserFactory

  • 单例模式:DefaultSelectStrategyFactory,DefaultSelectStrategy,DefaultEventExecutorChooserFactory

  • 策略模式:DefaultSelectStrategy

学到了什么?

  • 用上面的设计模式,可以把变化的地方变得容易扩展

  • Java定义好的线程池模型接口,我们可以重用,还可以根据自己的业务特征实现自己的线程池

    • 接口EventExecutorGroup重写父类接口ExecutorService,为了提示作用

    • NioEventLoopGroup中for (EventExecutor e: this),for-each只能适用于数组或者实现Iterable接口。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1414/viewspace-2797464/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2019-04-15

  • 博文量
    104
  • 访问量
    1015