美文网首页
netty源码分析(三) - NioEventLoop - 1创

netty源码分析(三) - NioEventLoop - 1创

作者: 进击的蚂蚁zzzliu | 来源:发表于2020-10-08 17:34 被阅读0次

概述

创建过程主要有以下4步:

  1. 创建NioEventLoopGroup
  2. 创建ThreadPerTaskExecutor
  3. 创建NioEventLoop
  4. 创建chooser
    下面对这四个步骤进行详细解析

1. 创建NioEventLoopGroup

NioEventLoopGroup创建.png

如上图构造器的调用过程,其中重点关注几个参数的默认值

  • selectorProvider:根据操作系统返回不同的provider
  • selectStrategyFactory:默认DefaultSelectStrategyFactory,后续run()中select时会用到(有task就通过selectNow取,没有返回-1)
  • nThread:NioEventLoop数组size(也就是线程数)为空时默认为当前cpu核数的两倍
  • chooserFactory:默认DefaultEventExecutorChooserFactory,后续通过该factory获取选择器(从NioEventLoop数组中选择一个跟新连接进行绑定)
  • args可变参数
    第一个参数selectorProvider;
    第二个参数selectStrategyFactory
    第三个参数(拒绝策略)默认RejectedExecutionHandler(抛出
    RejectedExecutionException异常)

2/3/4步代码如下(忽略了非主流程代码)

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
    if (executor == null) {
        //2. 创建ThreadPerTaskExecutor
        executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
    }
    //初始化大小为nThreads数组(NioEventLoop数组)
    children = new EventExecutor[nThreads];
    for (int i = 0; i < nThreads; i ++) {
        boolean success = false;
        try {
            //3. 创建NioEventLoop
            children[i] = newChild(executor, args);
            success = true;
        } catch (Exception e) {
            throw new IllegalStateException("failed to create a child event loop", e);
        } finally {
            //忽略
        }
    }
    //4. 创建chooser
    chooser = chooserFactory.newChooser(children);
}

2. 创建ThreadPerTaskExecutor

ThreadPerTaskExecutor 每次执行任务都会创建一个线程实体; 通过ThreadFactory进行构造,然后每次execute都会创建一个线程去运行

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;
    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        //构造方法传入threadFactory 即 newDefaultThreadFactory()返回
        this.threadFactory = ObjectUtil.checkNotNull(threadFactory, "threadFactory");
    }
    @Override
    public void execute(Runnable command) {
        //该执行器execute时,即通过threadFactory创建一个thread,然后start
        threadFactory.newThread(command).start();
    }
}

newDefaultThreadFactory(),线程工厂,通过newThread创建线程

public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
    //默认线程名:nioEventLoopGroup-group序号(从1自增)-线程号(从0自增)
    prefix = poolName + '-' + poolId.incrementAndGet() + '-';
    //是否守护线程:false
    this.daemon = daemon;
    //优先级:10
    this.priority = priority;
    this.threadGroup = threadGroup;
}

protected Thread newThread(Runnable r, String name) {
    //创建FastThreadLocalThread
    return new FastThreadLocalThread(threadGroup, r, name);
}
  • ThreadPerTaskExecutor:执行器实现jdk Executor接口
  • DefaultThreadFactory:创建执行线程的工厂,创建出FastThreadLocalThread,FastThreadLocalThread继承自jdk Thread,netty为了提高threadLocal性能设计,后续单独详解

3. 创建NioEventLoop

创建NioEventLoop放到数组中,新连接建立时会从数组中选取一个NioEventLoop进行绑定

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
                 EventLoopTaskQueueFactory queueFactory) {
        //newTaskQueue创建MpscQueue(一个消费者多个生产者的队列)
        super(parent, executor, false, newTaskQueue(queueFactory), newTaskQueue(queueFactory), rejectedExecutionHandler);
        //SelectorProvider.provider()
        this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");
        //DefaultSelectStrategy
        this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");
        //调用jdk openSelector方法打开一个选择器selector
        final SelectorTuple selectorTuple = openSelector();
        this.selector = selectorTuple.selector;
        this.unwrappedSelector = selectorTuple.unwrappedSelector;
    }
  • parent:NioEventLoopGroup
  • executor: ThreadPerTaskExecutor,第二步创建
  • selectorProvider:SelectorProvider.provider(),第一步初始化
  • strategy:DefaultSelectStrategy,第一步初始化
  • rejectedExecutionHandler:RejectedExecutionHandlers,第一步初始化
  • queueFactory:默认null
  • newTaskQueue:创建MpscQueue队列(后续详细讲解)

4. 创建chooser

后续新连接通过该选择器找到需要绑定的NioEventLoop

public EventExecutorChooser newChooser(EventExecutor[] executors) {
    //nThread是否 2 的倍数
    if (isPowerOfTwo(executors.length)) {
        //经过优化的方式获取数组下标:idx.getAndIncrement() & executors.length - 1
        return new PowerOfTwoEventExecutorChooser(executors);
    } else {
        //普通方式获取数组下标:Math.abs(idx.getAndIncrement() % executors.length)
        return new GenericEventExecutorChooser(executors);
    }
}
  • isPowerOfTwo:数组长度是否2的倍数
  • 是2的倍数:会通过优化的方式获取下标(通过位运算),性能更好;
  • 不是2倍数:普通方式获取下标(直接取模)
    两种方式最终达到的效果都是顺序依次获取,只不过2的倍数时可以通过位运算提升性能;

相关文章

网友评论

      本文标题:netty源码分析(三) - NioEventLoop - 1创

      本文链接:https://www.haomeiwen.com/subject/xzscpktx.html