netty的NioEventLoopGroup的创建过程

1.概述

EventLoopGroup是一个事件循环组,它管理着多个EventLoop,每个EventLoop都可以看成一个线程池(一般是单个线程,netty的几乎所有EventLoop实现类都是单线程池).

一个EventLoopGroup上会注册多个Channel,实际上它会根据内部EventExecutorChooser的算法,将一个Channel注册到其内部管理的一个具体的EventLoop,此EventLoop线程池处理这个Channel的所有IO事件和业务任务,而其他EventLoop线程池不能处理。

NioEventLoopGroup继承体系
在这里插入图片描述
NioEventLoop继承体系
在这里插入图片描述

2 NioEventLoopGroup创建流程

我们一般使用单参数的构造方法 NioEventLoopGroup(n)或无参构造方法 NioEventLoopGroup()

 public NioEventLoopGroup() {
        this(0);
    }

   public NioEventLoopGroup(int nThreads) {
        this(nThreads, (Executor) null);
    }

executor是null
selectorProvider是 SelectorProvider.provider()
selectStrategyFactory是 DefaultSelectStrategyFactory.INSTANCE
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                         final SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}


  
  再到父类MultithreadEventLoopGroupSelectorProvider.provider(),
  args参数包含SelectorProvider.provider()DefaultSelectStrategyFactory.INSTANCE,RejectedExecutionHandlers.reject()
   protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
   }

  再到构造方法 
    protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
    }
再到上级父类MultithreadEventExecutorGroup构造方法 
 protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
        this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
    }
最后到这个构造方法,这里开始真正的初始化
  protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
}
  

现在构造方法MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object… args) 的各个参数:

  • nThreads :new NioEventLoopGroup(n)中的n,表示要创建的线程数,也是线程池NioEventLoop的个数,因为一个NioEventLoop中只有一个线程(NioEventLoop继承于SingleThreadEventExecutor),
  • executor:这是真正的线程池。SingleThreadEventExecutor提交的第一个任务会让executor去执行,再让执行第一个任务时的线程Thread的引用赋值给SingleThreadEventExecutor的thread属性,以后新来的任务就可以放在SingleThreadEventExecutor中的队列(提交任务时的调用线程和SingleThreadEventExecutor的thread属性不是同一个线程),或立即执行(提交任务时的调用线程和SingleThreadEventExecutor的thread属性是同一个线程)。
  • chooserFactory: DefaultEventExecutorChooserFactory.INSTANCE 。构建EventExecutorChooser的工厂,EventExecutorChooser是决定某个Channel应该和哪个EventExecutor执行器(这里的实现类是NioEventLoop)相绑定。DefaultEventExecutorChooserFactory#newChooser返回是基于轮训算法的EventExecutorChooser
  • Args: 三个元素分别是SelectorProvider.provider()、DefaultSelectStrategyFactory.INSTANCE,RejectedExecutionHandlers.reject()

note: args中的三个元素

第一个:SelectorProvider是用来创建Selector,

第二个:SelectorProvider.provider()主要基于JDK spi机制发现相应的Provider,

第三个:DefaultSelectStrategyFactory.INSTANCE, 用来创建SelectStrategy,SelectStrategy决定EventExecutor线程池是等待Selector的事件到来还是线程继续空转、还是处理IO事件和业务功能。

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

  //上面传进来的executor是null,使用ThreadPerTaskExecutor,ThreadPerTaskExecutor的特点是每提交一个任务就创建一个线程去执行,任务会立即执行。
    if (executor == null) {
        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;
                    }
                }
            }
        }
    }
//根据构造方法参数传进来的chooserFactory,创建一个EventExecutor选择器,
  //这里是基于轮训算法的选择器
    chooser = chooserFactory.newChooser(children);

    final FutureListener<Object> terminationListener = new FutureListener<Object>() {
        @Override
        public void operationComplete(Future<Object> future) throws Exception {
            if (terminatedChildren.incrementAndGet() == children.length) {
                terminationFuture.setSuccess(null);
            }
        }
    };
//为每个EventExecutor创建线程终止的回调函数,当所有children终止时,当前的事件循环组能得到通知
    for (EventExecutor e: children) {
        e.terminationFuture().addListener(terminationListener);
    }

  //将所有EventExecutor包装为不可变集合
    Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);
}

从ThreadPerTaskExecuto的源码可以看出每提交一个任务就创建一个线程去执行,任务会立即执行。

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = ObjectUtil.checkNotNull(threadFactory, "threadFactory");
    }

    @Override
    public void execute(Runnable command) {
      //创建新线程并启动
        threadFactory.newThread(command).start();
    }
}

newChild()比较简单,就是根据参数new一个EventLoop

@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    EventLoopTaskQueueFactory queueFactory = args.length == 4 ? (EventLoopTaskQueueFactory) args[3] : null;
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
        ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2], queueFactory);
}


上面的 chooserFactory.newChooser(children)会根据children数据的长度返回两种不同的EventExecutorChooser,但它们都是基于取余的轮训算法

PowerOfTwoEventExecutorChooser针对children的长度为2的幂次方,它用位运算取余

PowerOfTwoEventExecutorChooser针对children的长度不是2的幂次方,它用常规取余%运算取余

@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
    if (isPowerOfTwo(executors.length)) {
        return new PowerOfTwoEventExecutorChooser(executors);
    } else {
        return new GenericEventExecutorChooser(executors);
    }
}
//确定长度是否为2的幂次方
private static boolean isPowerOfTwo(int val) {
    return (val & -val) == val;
}

private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;
    PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }
  
    @Override
    public EventExecutor next() {
      //和HashMap计算hash桶的原理类似,位运算比较快,(netty尽量在每个可能的地方进行优化,这就是netty的优秀之处的一个体现)
        return executors[idx.getAndIncrement() & executors.length - 1];
    }
}

private static final class GenericEventExecutorChooser implements EventExecutorChooser {
    private final AtomicLong idx = new AtomicLong();
    private final EventExecutor[] executors;
    GenericEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }
    @Override
    public EventExecutor next() {
      //不是2的幂次方,没法位运算取余常规取余`%`运算取余
        return executors[(int) Math.abs(idx.getAndIncrement() % executors.length)];
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值