源码共读(五)Netty 的连接创建是如何进行的

765 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情

我正在参与掘金会员专属活动-源码共读第一期,点击参与

分析 io.netty.channel.nio.NioEventLoop#run做了哪些事情

一、NioEventLoop概述

NioEventLoop做为Netty线程模型的核心部分,从本质上讲是一个事件循环执行器,每个NioEventLoop都会绑定一个对应的线程通过一个for(;;)循环来处理与 Channel 相关的 IO 操作, 包括 调用 select 等待就绪的 IO 事件、读写数据与数据的处理等;其次作为任务队列, 执行 taskQueue 中的任务, 例如eventLoop.schedule 提交的定时任务也是这个线程执行的。而NioEventLoopGroup顾名思义,它是维护了一组这样的事件循环器,这也是Netty基于Reactor模式的具体设计体现。

类层次结构如下

image.png

通过构造函数传入线程数量

image.png

NioEventLoopGroup最终的构造函数中包含以下元素

image.png

nThreads:传入的线程数

executor:线程执行器Executor接口,默认为空

selectorProvider:用于创建Selector的SelectorProvider

selectStrategyFactory: 策略工厂

RejectedExecutionHandlers.reject():自定义线程拒绝策略

父类会根据nThreads确定初始化线程数量,为0则会以当前核心线程数*2作为默认线程数量

image.png

接下来在MultithreadEventExecutorGroup的构造函数中我们会根据传入的线程数,去初始化和创建一组NioEventLoop

image.png

下面在MultithreadEventExecutorGroup构造函数中主要完成以下几个功能:

1、初始化ThreadPerTaskExecutor线程执行器,并传入一个线程创建工厂,用于NioEventLoop对应线程的创建

2、根据传入的线程数,初始化一个EventExecutor数组,用于放置创建的NioEventLoop对象

3、循环数组,通过newChild方法创建NioEventLoop对象。

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                        EventExecutorChooserFactory chooserFactory, Object... args) {
    if (nThreads <= 0) {
        throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
    }

    if (executor == null) {
    // 创建线程工厂,netty根据需要指定了线程的命名方式、优先级、是否是守护线程等属性
    // 该线程池没有任何队列,提交任务后,创建任何县城类型都是FastThreadLocalRunnable,立即start
        executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
    }

    //  初始化一组事项循环执行器
    children = new EventExecutor[nThreads];

    // 初始化线程数组
    for (int i = 0; i < nThreads; i ++) {
        boolean success = false;
        try {
            children[i] = newChild(executor, args);
            success = true;
        } catch (Exception e) {
            // TODO: Think about if this is a good exception type
            throw new IllegalStateException("failed to create a child event loop", e);
        } finally {
            if (!success) {
                for (int j = 0; j < i; j ++) {
                    children[j].shutdownGracefully();
                }

                for (int j = 0; j < i; j ++) {
                    EventExecutor e = children[j];
                    try {
                        while (!e.isTerminated()) {
                            e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                        }
                    } catch (InterruptedException interrupted) {
                        // Let the caller handle the interruption.
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
    }

继续跟踪newChild(),看到他返回一个EventLoop对象 image.png

通过上面的代码,初始化NioEventLoop主要完成几个功能

1.保存线程执行器ThreadPerTaskExecutor 2.创建一个selector 3.基于LinkedBlockingQueue创建一个taskQueue任务队列,用于保存要执行的任务