NOTE

2.70 创建NioEventLoop数组

1. 要分析的代码 2. 传入NioEventLoop构造的参数 我们接着看 newChild(executor, args) ,跳转到 - NioEventLoopGroup#newChild 调用构造方法传入的参数 - this是NioEventLoopGroup自己 - executor是刚刚

Java创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 要分析的代码

//NioEventLoopGroup池子中的NioEventLoop保存在数组中
children = new EventExecutor[nThreads];

children[i] = newChild(executor, args);

2. 传入NioEventLoop构造的参数

我们接着看newChild(executor, args),跳转到

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

调用构造方法传入的参数

  • this是NioEventLoopGroup自己
  • executor是刚刚创建的ThreadPerTaskExecutor,说明所有NioEventLoop共享是同一个线程池
  • SelectorProvider用于创建jdk nio的selector
  • select策略为DefaultSelectStrategy.INSTANCE
  • 拒绝策略

3. NioEventLoop是个单线程的线程池

由图看出NioEventLoop也是个线程池,可以把任务封装成Runnable丢给他执行。 奇怪的是他继承的SIngleThreadEventLoop,从名字可以看出是个单线程的线程池?

4. NioEventLoop构造方法

4.1. 创建selector

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
             SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
	//父类SingleThreadEventLoop的构造
    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
    //unwrappedSelector = provider.openSelector();
    final SelectorTuple selectorTuple = openSelector();
    selector = selectorTuple.selector;
    unwrappedSelector = selectorTuple.unwrappedSelector;
    //保存选择策略
    selectStrategy = strategy;
}

这里创建了selector,说明每个NioEventLoop都有一个Selector与之对应

继续看父类SingleThreadEventLoop的构造

  • SingleThreadEventLoop
protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
								boolean addTaskWakesUp, int maxPendingTasks,
								RejectedExecutionHandler rejectedExecutionHandler) {

	//父类SingleThreadEventExecutor
	super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
	//new LinkedBlockingQueue<Runnable>(maxPendingTasks);
	tailTasks = newTaskQueue(maxPendingTasks);
}

继续看父类SingleThreadEventExecutor

4.2. 创建保存任务的队列

  • SingleThreadEventExecutor
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
                                    boolean addTaskWakesUp, int maxPendingTasks,
                                    RejectedExecutionHandler rejectedHandler) {
	//AbstractScheduledEventExecutor->AbstractEventExecutor
    super(parent);
    this.addTaskWakesUp = addTaskWakesUp;
    this.maxPendingTasks = Math.max(16, maxPendingTasks);
    this.executor = ObjectUtil.checkNotNull(executor, "executor");
	//保存任务的队列
	//new LinkedBlockingQueue<Runnable>(maxPendingTasks);
    taskQueue = newTaskQueue(this.maxPendingTasks);
    rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

taskQueue用于外部线程执行netty的一些任务的时候,如果不是在NioEventLoop执行,就会塞到这个任务队列里,然后由NioEventLoop对应的线程取出来执行