netty核心组件之EventLoopGroup和EventLoop

这节我们着重介绍netty最为核心的组件EventLoopGroup和EventLoop

EventLoopGroup:顾名思义就是EventLoop的组,下面来看它们的继承结构

 

 

 

 

 

 在netty中我们可以把EventLoop看做一个线程,当然线程不单是jdk中的的线程,它们都从Executor一路继承过来,NioEventLoop继承SinfleThreadEventLoop,从名字可以看出它是一个单线程的EventLoop,

我们先来看NioEventLoop是如何构造的

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);
}

NioEventLoop构造函数非常多,每个参数都可以定制,我就不全贴出来了,最后回到这个参数最全的构造函数,下面我们挨个解释每个参数的作用

  • nThreads: 线程数,对应EventLoop的数量,为0时 默认数量为CPU核心数*2
  • executor: 这个我们再熟悉不过,最终用来执行EventLoop的线程
  • chooserFactor: 当我们提交一个任务到线程池,chooserFactor会根据策略选择一个线程来执行
  • selectorProvider:用来实例化jdk中的selector,没一个EventLoop都有一个selector
  • selectStrategyFactory:用来生成后续线程运行时对应的选择策略工厂
  • rejectedExecutionHandler:跟jdk中线程池中的作用一样,用于处理线程池没有多余线程的情况,默认直接抛出异常

接着我们进入父类MultithreadEventLoopGroup的构造函数

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) {
        executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
    }
    // 创建nThreads大小的EventLoop数组
    children = new EventExecutor[nThreads];

    for (int i = 0; i < nThreads; i ++) {
        boolean success = false;
        try {
            // 创建具体的EventLoop,会调用子类NioEventLoopGruop中的方法
            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;
                    }
                }
            }
        }
    }
    // 把刚才创建好的EventLoop提供给EventExecutorChooser,用于后续选择
    chooser = chooserFactory.newChooser(children);

    // 添加一个EventLoop监听器,用来监听EventLoop终止状态
    final FutureListener<Object> terminationListener = new FutureListener<Object>() {
        @Override
        public void operationComplete(Future<Object> future) throws Exception {
            if (terminatedChildren.incrementAndGet() == children.length) {
                terminationFuture.setSuccess(null);
            }
        }
    };

    for (EventExecutor e: children) {
        // 循环加入
        e.terminationFuture().addListener(terminationListener);
    }
    // 将EventLoop数组转成一个只读的set
    Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);
}

我们继续跟到父类NioEventLoopGroup中的newChild

protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
        ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}

可以看出先用来创建EventLoopGroup的参数其实都是用来创建EventLoop的,我们继续跟NioEventLoop的构造

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
    super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
    if (selectorProvider == null) {
        throw new NullPointerException("selectorProvider");
    }
    if (strategy == null) {
        throw new NullPointerException("selectStrategy");
    }
    provider = selectorProvider;
    // 创建selector,由此可见每一个EventLoop都会有一个selector
    final SelectorTuple selectorTuple = openSelector();
    selector = selectorTuple.selector;
    unwrappedSelector = selectorTuple.unwrappedSelector;
    selectStrategy = strategy;
}

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
                                        boolean addTaskWakesUp, int maxPendingTasks,
                                        RejectedExecutionHandler rejectedHandler) {
    super(parent);
    this.addTaskWakesUp = addTaskWakesUp;
    this.maxPendingTasks = Math.max(16, maxPendingTasks);
    this.executor = ObjectUtil.checkNotNull(executor, "executor");
    // 用来添加task的阻塞队列 链表结构
    taskQueue = newTaskQueue(this.maxPendingTasks);
    rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

 

这里我们只是创建EventLoop,同时设置了执行的线程池、selector、taskQueue,并添加一个监听器用来监听它们的关闭状态,当所有线程都全部处于关闭状态terminationFuture会被置为true,到此还是没有实际创建可执行的thread。

 后续我们在介绍channel的时候就知道EventLoop和channel如何建立关系,什么时候执行线程,我们姑且把EventLoop当做一个可执行runnable的netty线程

posted @ 2020-12-23 22:21  努力工作的小码农  阅读(935)  评论(0编辑  收藏  举报