16-EventLoopGroup整体

EventLoopGroup整体

  • EventLoop,字面意思来看是事件循环,内部是一个线程;Netty 是Reactor线程模型的一种实现,结合Netty 中的线程模型和 Reactor 模型来理解EventLoop 在Netty 中的作用;
  • EventLoopGroup,是一组EventLoop,内部有一组EventLoop 线程
  • 本文先从整体来看看:EventLoopGroup

一、EventLoopGroup和Reactor线程模型

1.1 Reactor 线程模型

  • 单线程模型:接受连接和IO处理在一个线程
  • 多线程模型:接受连接和IO处理在不同线程,一个线程负责接受连接,另外一个线程池负责IO处理
  • 主从模型:一个线程池负责接受连接,另一个线程池负责IO处理

1.2 EventLoopGroup对模型实现

  • Netty server端的三种Reactor模型实现:
  • 单线程模型
    单线程模型:
    EventLoopGroup single = new NioEventLoopGroup(1);
    bootstrap.group(single);
  • 多线程模型
    多线程模型:
    NioEventLoopGroup boss = new NioEventLoopGroup(1);
    NioEventLoopGroup worker = new NioEventLoopGroup();
    bootstrap.group(boss, worker);
  • 主从模型
    主从线程模型:
    NioEventLoopGroup boss = new NioEventLoopGroup(4);
    NioEventLoopGroup worker = new NioEventLoopGroup();
    bootstrap.group(boss, worker);

二、上层类和接口

  • 我们先看看整体的继承关系,其中 NioEventLoop和 NioEventLoopGroup 是最底层的子类,从顶层来看,EventExecutorGroup 是前面两个类共同的父接口,并且 EventExecutorGroup 是继承了JDK中的 ScheduledExecutorService接口,ScheduledExecutorService 表示具备周期性执行或者一段时间后延迟执行的线程池,JDK基本线程池之一的 ScheduledThreadPoolExecutor 就是它的实现类,由此我们可以基本的知道 EventLoop和EventLoopGroup 本质上都是一种线程池,具备线程池的执行任务的功能和特性。

  • EventLoopGroup主要包含2个方面的功能:注册 Channel和执行一些 Runnable任务。

  • EventLoop 内部对应着一个线程,且整个生命周期中对应的线程不会发生改变,

  • 我们先看看接口大致功能,再从 EventLoopGroup 的功能入手去分析,下面是整个继承体系;

在这里插入图片描述

2.1 EventExecutorGroup

  • 前面提到了 EventExecutorGroup 是很关键的一个接口,它继承了JDK的原生线程池接口,同时又是 EventLoop和EventLoopGroup 的公共父接口,它也定义了一系列的接口方法,对于继承自 Executor、ExecutorService和ScheduledExecutorService 里面的方法我们不做关注,有兴趣可以参阅线程池部分的源码。
/**
 * EventExecutor(事件执行器)分组接口,提供处理EventExecutor生命周期的方法,
 * 比如关闭方法shutdownGracefully、terminationFuture(全部EventExecutor关闭之后会调用对应的Future)
 * isShuttingDown:判断全部的EventExecutor是否都已经关闭
 * 另外提供了next方法用于返回一个EventExecutor
 * 另外他重写了继承自父类的一些方法,默认也是空实现,避免子类需要实现全部的方法
 */
public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor> {

    boolean isShuttingDown();
    Future<?> shutdownGracefully();
    Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit);
    Future<?> terminationFuture();

    /**
     *这个方法很关键没返回内部管理的一个 EventExecutor 对象,用于执行任务
     * Returns one of the {@link EventExecutor}s managed by this {@link EventExecutorGroup}.
     */
    EventExecutor next();

    //下面的@Override方法都是继承自父类的方法
    
    @Override
    Iterator<EventExecutor> iterator();

    @Override
    Future<?> submit(Runnable task);

    @Override
    ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);

    @Override
    ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);

    @Override
    ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
}
  • 可以看到 EventExecutorGroup 内部定义从线程池接口继承了很多执行定时任务和提交任务的方法,很多异步的方法返回的是 Future 对象,不过这个 Future 对象是Netty 框架自身定义的,而非JDK 的
  • 这里需要注意的是 next(); 方法,它用于返回一个 EventExecutor 事件执行器,后面在子类中可以看到对于submit和schedule 等方法的实现就是通过next 获取到执行器后执行的,这里的next 在后面可以看到是通过策略 EventExecutorChooser 来选择的
  • 下面我们都分析 EventExecutorGroup 的子类和派生子类

2.2 AbstractEventExecutorGroup

  • AbstractEventExecutorGroup 实现了 EventExecutorGroup,将其中的执行任务方法逻辑做了初步实现。
  • 大致方法包括:
1.submit提交任务,并选择一个 EventExecutor 执行
2.schedule 提交定时任务,并选择一个 EventExecutor 执行 
3.invokeAll:调用全部方法,并选择一个 EventExecutor 执行 (继承自线程池的方法)
4.invokeAny:调用任意,并选择一个 EventExecutor 执行  (继承自线程池的方法)
5.execute:执行普通任务
6.shutdown / shutdownGracefully:关闭
  • 部分方法如下:
/**
 * EventExecutorGroup的抽象实现类
 * 
 * 里面的实现基本都是基于 EventExecutorGroup 的一个 next 方法来做的,next获得一个EventExecutor(事件执行器),由
 * 这个执行器来执行任务
 * 
 * EventExecutor 也是 EventExecutorGroup 的一个子类,因此获得了这些方法,对应最终的实现类有NioEventLoop,内部是
 * 有一个线程对象的
 */
public abstract class AbstractEventExecutorGroup implements EventExecutorGroup {

    /**
     *通过next获得一个 EventExecutor 事件执行器,由事件执行器执行该方法
     * */
    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        return next().submit(task, result);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return next().submit(task);
    }

    @Override
    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
        return next().schedule(command, delay, unit);
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
        return next().scheduleAtFixedRate(command, initialDelay, period, unit);
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
        return next().scheduleWithFixedDelay(command, initialDelay, delay, unit);
    }

    @Override
    public Future<?> shutdownGracefully() {
        return shutdownGracefully(DEFAULT_SHUTDOWN_QUIET_PERIOD /* 2 */, DEFAULT_SHUTDOWN_TIMEOUT /* 15 */, TimeUnit.SECONDS);
    }

    @Override
    public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
        return next().invokeAll(tasks);
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return next().invokeAny(tasks, timeout, unit);
    }

    @Override
    public void execute(Runnable command) {
        next().execute(command);
    }
}

2.3 MultithreadEventExecutorGroup

  • MultithreadEventExecutorGroup 从名字来看是基于多线程的 EventExecutorGroup,内部主要逻辑是完成内部事件执行器的初始化
2.3.1 概览
  • MultithreadEventExecutorGroup 内部是多线程,一个线程对应一个 EventExecutor,因此内部很多操作都是基于一个 EventExecutor 数组来操作的,包括初始化以及各种状态判断等
/**
 * 基于多线程的 EventExecutor ( 事件执行器 ) 的分组抽象类,用多线程处理任务
 *
 * Abstract base class for {@link EventExecutorGroup} implementations that handles their tasks
 * with multiple threads atthe same time.
 */
public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {

    /**
     * EventExecutor 数组,可以理解为一个 EventExecutor 对应一个线程
     */
    private final EventExecutor[] children;

    /**
     * (不可变)只读的EventExecutor数组
     */
    private final Set<EventExecutor> readonlyChildren;

    /**
     * 已终止的EventExecutor数量
     */
    private final AtomicInteger terminatedChildren = new AtomicInteger();

    /**
     * 用于终止EventExecutor的异步 Future
     */
    private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);

    /**
     * EventExecutor选择器,可以定义
     */
    private final EventExecutorChooserFactory.EventExecutorChooser chooser;

    /**
     * 获取一个事件执行器,用选择器来选一个,默认是轮询
     */
    @Override
    public EventExecutor next() {
        return chooser.next();
    }

    @Override
    public Iterator<EventExecutor> iterator() {
        return readonlyChildren.iterator();
    }

    /**
     * Return the number of {@link EventExecutor} this implementation uses. This number is the maps
     * 1:1 to the threads it use.
     */
    public final int executorCount() {
        return children.length;
    }

    /**
     * 创建一个 EventExecutor ,后续next方法返回的就是EventExecutor,这个方法会被服务于 MultithreadEventExecutorGroup的线程调用
     * Create a new EventExecutor which will later then accessible via the {@link #next()}  method. This method will be
     * called for each thread that will serve this {@link MultithreadEventExecutorGroup}.
     */
    protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;

    @Override
    public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
        for (EventExecutor l : children) {
            l.shutdownGracefully(quietPeriod, timeout, unit);
        }
        return terminationFuture();
    }

    @Override
    public Future<?> terminationFuture() {
        return terminationFuture;
    }

    @Override
    public boolean isShutdown() {
        for (EventExecutor l : children) {
            if (!l.isShutdown()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        long deadline = System.nanoTime() + unit.toNanos(timeout);
        loop:
        for (EventExecutor l : children) {
            for (; ; ) {
                long timeLeft = deadline - System.nanoTime();
                if (timeLeft <= 0) {
                    break loop;
                }
                if (l.awaitTermination(timeLeft, TimeUnit.NANOSECONDS)) {
                    break;
                }
            }
        }
        return isTerminated();
    }
}
2.3.2 构造方法
  • 构造方法主要是对内部的 EventExecutor 数组做初始化,以及初始化过程的异常处理
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
        //1.线程数不能小于0
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }

        //2.创建执行器,默认是每个任务一个线程
        if (executor == null) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }

        //3.创建children EventExecutor 数组
        children = new EventExecutor[nThreads];

        //4.循环创建 EventExecutor 数组中的EventExecutor
        for (int i = 0; i < nThreads; i++) {
            //是否创建成功
            boolean success = false;
            try {
                //5.创建EventExecutor对象,newChild是抽象方法交给子类实现,
                //不同的子类创建的执行器是不同类型的,有 NioEventLoop、KQueueEventLoop等
                children[i] = newChild(executor, args);
                //6.标记创建成功
                success = true;
            } catch (Exception e) {
                //7.创建失败抛出IllegalStateException异常
                //TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
                //8.创建失败,关闭所有已创建的 EventExecutor;注意这个成功的标志位 success 是每次循环进来都会赋值,
                //因此相当于每一次都会去判断是否失败,只要有一个失败,就会把前面的创建好的EventExecutor关闭
                if (!success) {
                    //9.关闭所有已创建的 EventExecutor
                    for (int j = 0; j < i; j++) {
                        children[j].shutdownGracefully();
                    }
                    //10.确保所有已创建的 EventExecutor 已关闭,异常的话就等待直到关闭掉
                    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;
                        }
                    }
                }
            }
        }

        //11.创建 EventExecutor 选择器,默认选择策略是轮询
        chooser = chooserFactory.newChooser(children);

        //12.创建监听器,用于 EventExecutor 终止时的监听
        final FutureListener<Object> terminationListener = new FutureListener<Object>() {

            @Override
            public void operationComplete(Future<Object> future) throws Exception {
                //已经终止的EventExecutor数量等于总数
                if (terminatedChildren.incrementAndGet() == children.length) {
                    // 设置结果,并通知监听器们。
                    terminationFuture.setSuccess(null);
                }
            }

        };

        //13.给每个EventExecutor设置监听器
        for (EventExecutor e : children) {
            e.terminationFuture().addListener(terminationListener);
        }

        //14.创建不可变(只读)的EventExecutor数组,通过工具类返回一个只读的Set,里面包含的 EventExecutor和EventExecutor 数组是一样的
        Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
        Collections.addAll(childrenSet, children);
        readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }
2.3.3 ThreadPerTaskExecutor
  • ThreadPerTaskExecutor 是默认的事件执行器,每一个任务创建一个新的线程去执行,它直接继承了 JDK的 Executor接口
/**
 * 执行器实现类,每个任务创建一个线程执行
 */
public final class ThreadPerTaskExecutor implements Executor {

    /**
     * 线程工厂
     */
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        if (threadFactory == null) {
            throw new NullPointerException("threadFactory");
        }
        this.threadFactory = threadFactory;
    }

    /**
     * 执行任务
     * @param command 任务
     */
    @Override
    public void execute(Runnable command) {
        threadFactory.newThread(command).start();
    }
}
  • 关于 ThreadFactory ,有兴趣可以看看Netty中的DefaultThreadFactory,代码比较简单,就是简单的实现了一个命名规则的线程工厂,内部创建的线程都是FastThreadLocalThread对象,FastThreadLocalThread是Thread的子类,是Netty扩展的线程对象,能够快速的访问 FastThreadLocal 变量,这个有时间后续小结一下,这里简单带一下;

三、EventLoopGroup

  • EventLoopGroup 接口包含了注册方法和next方法,注册方法将Channel 注册到一个EventLoo,next 方法用于在 EventLoopGroup 中获取一个 EventLoop;
  • 接口代码
/**
 * EventLoop分组接口,提供了EventLoop的获取方法(next)和将Channel注册到EventLoop的方法
 */
public interface EventLoopGroup extends EventExecutorGroup {

    /**
     * 获取一个EventLoop来使用
     */
    @Override
    EventLoop next();

    /**
     * 注册一个Channel到EventLoop上,注册成功后ChannelFuture会收到一个通知
     */
    ChannelFuture register(Channel channel);

    ChannelFuture register(ChannelPromise promise);
}

3.1 EventLoopGroup功能

3.1.1 注册Channel
  • 前面已经提到,EventLoopGroup 的一个重要功能就是将 Channel 注册到 EventLoop,注册动作实际上是由内部的EventLoop完成的。EventLoopGroup会通过 next 方法选择一个内部的 EventLoop 来执行注册动作(后面会介绍选择策略),最底层本质是在EventLoop的实现子类的内部维护一个集合,集合内部保存注册在自己身上的 Channel 对象。这里可以简单跟一下源码,可能有点绕。

  • 首先我们看到 EventLoopGroup的注册功能是在子类 MultithreadEventLoopGroup 实现的,代码如下:

//MultithreadEventLoopGroup 内部选择一个EventLoop来注册
    
    @Override
    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }
    
    @Override
    public EventLoop next() {
        return (EventLoop) super.next();
    }
  • 在 register 方法打上断点启动后调用栈如下:

在这里插入图片描述

  • 大致的调用流程是:
AbstractBootstrap#bind() ->
    -> AbstractBootstrap#doBind()
        -> AbstractBootstrap#initAndRegister()
            -> MultithreadEventLoopGroup#register 
                -> EventLoopGroup#register(io.netty.channel.Channel)
                    -> SingleThreadEventLoop#register(io.netty.channel.ChannelPromise)
  • 1.首先是启动器的 bind 方法,进入 bind 逻辑,调用 AbstractBootstrap 的 bind 和 doBind 方法
  • 2.然后进入 initAndRegister 方法完成注册逻辑,内部会通过 config 配置对象获取到 EventLoopGroup 对象,调用 EventLoopGroup 的 register 方法
  • 3.往后继续走 MultithreadEventLoopGroup 的register 方法,通过next 获取一个内部的 EventLoop 对象,执行 register,然后就走到了 EventLoop 的register 方法
  • 4.走到 EventLoop 的实现类 SingleThreadEventLoop 的 register 方法
  • 5.继而走到与 SingleThreadEventLoop 所关联的 AbstractChannel 的 register 方法
  • 6.最后注册逻辑走到 AbstractNioChannel 的register 方法,(核心代码如下):我们看看到注册的代码是不是和NIO几乎一样,形如:channel.register(selector) 返回selectKey,有兴趣可以查阅参考文章[3]的2.2 示例代码
@Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (; ; ) {
            try {
                //这段代码,是不是和NIO代码很相似
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
                return;
            } catch (CancelledKeyException e) {
                // TODO TODO 1003 doRegister 异常
                if (!selected) {
                    // Force the Selector to select now as the "canceled" SelectionKey may still be
                    // cached and not removed because no Select.select(..) operation was called yet.
                    eventLoop().selectNow();
                    selected = true;
                } else {
                    // We forced a select operation on the selector before but the SelectionKey is still cached
                    // for whatever reason. JDK bug ?
                    throw e;
                }
            }
        }
    }
3.1.2 执行Runnable任务
  • EventLoopGroup 继承了 EventExecutorGroup,前面分析了EventExecutorGroup 继承了线程池的许多接口,通过 EventLoopGroup 的submit 或者 schedule 等方法能够向 EventLoopGroup 提交任务,对应的任务会被 EventLoopGroup 选择一个内部的 EventLoop 来执行,而选择的策略和前面一样,通过 next() 方法实现, 异步任务返回一个 Future 对象,

  • 这里需要额外提一下的是 EventExecutorGroup 继承了JDK的 ScheduledExecutorService 方法,由此实现了 submit,schedule 等执行任务的方法,但是返回的对象改变了,父类返回的是JDK的Future对象,EventExecutorGroup 返回的是 Netty自己的Future对象。

  • 这里大致的回顾最前面的继承图可以看出来,纵向大致分为两块,右边红圈部分是Group相关的,包括 EventExecutorGroup 和 EventLoopGroup 等,左边没有圈起来的基本上就是 执行器相关,就是被Group 管理的,比如 EventExecutor和 EventLoop。然后发现左边的继承了右边的接口,比如 EventExecutor 继承了 EventExecutor, EventLoop 继承了 EventLoopGroup,因为Group 所提供的功能,本质上内部都是调用内部持有的具体执行器来做,比如submit,register 等,因此左边的也实现了右边的接口,右边的只是管理者,接口通过netx 其实还是委托给内部的对象来执行;

3.2 关于next

  • 这里屡一下next这个方法,这个方法对于 EventLoopGroup 来说是获取一个内部的 EventLoop,因为前者是一组后者,而在顶层接口 EventExecutorGroup 中也有一个next 方法用于获取 EventExecutor,因为前者也是是一组后者。这两组对象是不是很相似,我们看看继承图,发现其实:EventLoopGroup 就是对应着 EventExecutorGroup,而 EventLoop 也对应着 EventExecutor

在这里插入图片描述

  • 从上图看到,二者就是对应的关系,而且 EventExecutorGroup的next 方法在 MultithreadEventExecutorGroup 中得到实现,而 EventLoopGroup 的实现类 MultithreadEventLoopGroup 直接从 MultithreadEventLoopGroup继承到实现的方法,将获取到的 EventExecutor直接向下转型成 EventLoop

    //MultithreadEventExecutorGroup中对 EventExecutorGroup 的 next 方法的实现
    /**
     * 获取一个事件执行器,用选择器来选一个,默认是轮询
     */
    @Override
    public EventExecutor next() {
        return chooser.next();
    }

    /**
     *MultithreadEventLoopGroup中对 EventLoopGroup 的 next 方法的实现,直接调用父类也就
     *是 MultithreadEventExecutorGroup的next方法,将获取到的 EventExecutor转换为 EventLoop
    */
    @Override
    public EventLoop next() {
        return (EventLoop) super.next();
    }

3.3 EventExecutorChooser

  • 这里的 next()方法使用一个选择策略去选择,对应的策略接口是:EventExecutorChooser 它是:EventExecutorChooserFactory的一个内部类,而后者是创建策略的工厂对象,在NioEventLoop 的构造方法可以将 EventExecutorChooserFactory 作为参数传进去来自定义选择策略。

  • EventExecutorChooserFactory 和 EventExecutorChooser 接口

/**
 * EventExecutorChooser 工厂接口,可以创建:EventExecutorChooser 事件执行选择器
 * Factory that creates new {@link EventExecutorChooser}s.
 */
@UnstableApi
public interface EventExecutorChooserFactory {

    /**
     * 工厂接口用于创建一个 EventExecutorChooser 选择器对象
     * Returns a new {@link EventExecutorChooser}.
     */
    EventExecutorChooser newChooser(EventExecutor[] executors);

    /**
     * EventExecutorChooser 选择器接口
     * Chooses the next {@link EventExecutor} to use.
     */
    @UnstableApi
    interface EventExecutorChooser {

        /**
         * 选择器用于获取一个事件执行器
         * Returns the new {@link EventExecutor} to use.
         */
        EventExecutor next();
    }
}
  • EventExecutorChooser 的实现有两种,都是采用轮询的方式获取,不过计算方式有区别,一种是取余,一种是与运算(长度为2的幂次时)
/**
 * 默认 EventExecutorChooser 工厂实现类,简单轮询选择 EventExecutor
 * <p>
 * Default implementation which uses simple round-robin to choose next {@link EventExecutor}.
 */
@UnstableApi
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {

    /**
     * 单例
     */
    public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();

    private DefaultEventExecutorChooserFactory() {
    }

    @SuppressWarnings("unchecked")
    @Override
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        //长度为2的幂次,就使用与运算
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }

    private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;
    }

    private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {

        /**
         * 自增序列
         */
        private final AtomicInteger idx = new AtomicInteger();
        /**
         * EventExecutor 数组
         */
        private final EventExecutor[] executors;

        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        /**
         * 自增与运算,相当于轮询,其实和则增取余差不多,只不过当 executors 长度为2的幂次时,取余运算和
         * 这里的与运算等价,不过与云运算性能更好,类似于 hashMap 里面的,非常细微的优化
         * 在前面的 newChooser 方法选择的时候会判断如果长度是2的幂次就选这个,不是就选择轮询
         */
        @Override
        public EventExecutor next() {
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    }

    private static final class GenericEventExecutorChooser implements EventExecutorChooser {

        /**
         * 自增序列
         */
        private final AtomicInteger idx = new AtomicInteger();
        /**
         * EventExecutor 数组
         */
        private final EventExecutor[] executors;

        GenericEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        /**
         * 自增取余,相当于轮询
         */
        @Override
        public EventExecutor next() {
            return executors[Math.abs(idx.getAndIncrement() % executors.length)];
        }
    }
}

3.4 MultithreadEventLoopGroup

  • MultithreadEventLoopGroup:它一方面继承了MultithreadEventExecutorGroup,是一个多线程的事件执行器,另一方面实现了 EventLoopGroup,因此是一个多线程版本的:EventLoopGroup

在这里插入图片描述

  • MultithreadEventLoopGroup 基本是就是坐吃现成,所有的方法都在父类 MultithreadEventExecutorGroup 实现好了,继承自 EventLoopGroup 的方法只需要通过父类的 next 选择一个 EventLoop 执行就搞定了,代码不多;
/**
 * 多线程版本的 EventLoopGroup 分组抽象类,实现 EventLoopGroup接口并继承MultithreadEventExecutorGroup,使用多线程同时处理任务
 * <p>
 * Abstract base class for {@link EventLoopGroup} implementations that handles their tasks with multiple threads at
 * the same time.
 * <p>
 * 从代码分析来看,MultithreadEventLoopGroup 本身没有做太多事情,因为多线程相关的初始化工作以及next 选择执行器的方法都
 * 已经在父类 MultithreadEventExecutorGroup 中实现好了,继承自 EventLoopGroup 的需要执行的方法则是通过 next 方法获
 * 取具体的 EventLoop 对象来执行
 * <p>
 */
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);

    /**
     * 默认EventLoop线程数,通过static代码块赋值,CPU核心数的2倍
     * 为什么是2,因为线程超线程技术一个核心可以对应两个线程
     */
    private static final int DEFAULT_EVENT_LOOP_THREADS;

    static {
        DEFAULT_EVENT_LOOP_THREADS =
                Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

        if (logger.isDebugEnabled()) {
            logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
        }
    }

    //下面是各种重载的构造方法

    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }

    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, ThreadFactory, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
    }

    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor,
     * EventExecutorChooserFactory, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, chooserFactory, args);
    }


    /**
     * 默认是Netty 自定义的命名线程池
     */
    @Override
    protected ThreadFactory newDefaultThreadFactory() {
        return new DefaultThreadFactory(getClass(), Thread.MAX_PRIORITY);
    }

    /**
     * 通过父类 MultithreadEventExecutorGroup 已经实现好的 next 方法获取EventExecutor 事
     * 件执行器然后转型为 EventLoop,父类的next 方法是对 EventExecutorGroup 中 next 方法的实现
     */
    @Override
    public EventLoop next() {
        return (EventLoop) super.next();
    }

    /**
     * 下面是继承自EventLoopGroup 和 MultithreadEventExecutorGroup 的方法,基本也是通过next来实
     * 现的,或者不实现
     */
    @Override
    protected abstract EventLoop newChild(Executor executor, Object... args) throws Exception;

    @Override
    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }

    @Override
    public ChannelFuture register(ChannelPromise promise) {
        return next().register(promise);
    }

    @Deprecated
    @Override
    public ChannelFuture register(Channel channel, ChannelPromise promise) {
        return next().register(channel, promise);
    }
}
  • 需要注意的是默认线程数是 CPU核心 * 2,因为超线程技术一个核心可以处理两个线程 (不过超线程技术达到的性能并不等于两个核心,还需要硬件以及操作系统的相关执行)

3.5 NioEventLoopGroup

  • NioEventLoopGroup 是本文涉及到的唯一一个实现类,前面都是上层接口和抽象类,NioEventLoopGroup 是我们代码中具体创建的对象,因为上层的各种实现,到这代码已经不多了。

  • 在分析之前我们看看 NioEventLoopGroup 和其父类 MultithreadEventLoopGroup 的关系以及其他的兄弟实现类,MultithreadEventLoopGroup 代表多线程的实践循环组,其他他有很多实现,(如下), 换言之这些实现类都是基于多线程实现了EventLoopGroup,但是具体适用场景有所不同:

在这里插入图片描述

MultithreadEventLoopGroup子实现类功能
NioEventLoopGroup使用Selector和Channel的NIO实现
DefaultEventLoopGroup默认实现,用于本地通信
EpollEventLoopGroup只适用于Linux系统,底层使用 epoll
KQueueEventLoopGroup没有注释,暂不清楚
  • 源码
/**
 * NioEventLoop 分组的实现类,多线程,基于 Channel和Selector 的NIO实现
 *
 * NioEventLoop 本身代码不多,主要方法是:
 * 1.构造方法,支持各种参数的构造方法
 * 2.IO时间比例设置,调用内部的 NioEventLoop 来设置
 * 3.重建 selector,解决 epoll bug
 * 4.创建执行器,创建的是 NioEventLoop 实例,创建过程会用到SelectorProvider
 * <p>
 * {@link MultithreadEventLoopGroup} implementations which is used for NIO {@link Selector} based {@link Channel}s.
 */
public class NioEventLoopGroup extends MultithreadEventLoopGroup {

    /**
     * 构造方法,很多重载的,部分省略
     * Create a new instance using the default number of threads, the default {@link ThreadFactory} and
     * the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
     */
    public NioEventLoopGroup() {
        this(0);
    }

    /**
     * 这个构造方法参数最多
     *
     * */
    public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                             final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory,
                             final RejectedExecutionHandler rejectedExecutionHandler) {
        super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler);
    }

    /**
     * 设置事件循环中期望的IO比例,默认50,此时IO和非IO时间各占一半左右
     * <p>
     * Sets the percentage of the desired amount of time spent for I/O in the child event loops.  The default value is
     * {@code 50}, which means the event loop will try to spend the same amount of time for I/O as for non-I/O tasks.
     */
    public void setIoRatio(int ioRatio) {
        for (EventExecutor e : this) {
            ((NioEventLoop) e).setIoRatio(ioRatio);
        }
    }

    /**
     * 用新创建的 Selector 替换子事件循环中的 Selector,解决 epoll 的bug。(导致CPU 100%)
     * Replaces the current {@link Selector}s of the child event loops with newly created {@link Selector}s to work
     * around the  infamous epoll 100% CPU bug.
     */
    public void rebuildSelectors() {
        for (EventExecutor e : this) {
            ((NioEventLoop) e).rebuildSelector();
        }
    }

    /**
     * 创建 EventLoop,内部构造的是 NioEventLoop
     * 父类 MultithreadEventExecutorGroup 初始多线程的时候调用该类实现
     */
    @Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        return new NioEventLoop(
                this,
                executor,
                (SelectorProvider) args[0],
                ((SelectStrategyFactory) args[1]).newSelectStrategy(),
                (RejectedExecutionHandler) args[2]);
    }
}
  • 这里主要是 newChild 这个方法,这个方法会被父类 MultithreadEventExecutorGroup 调用,用于初始化多线程的执行器,父类调用会将参数传过来,而父类的参数则是在构造 NioEventLoopGroup 的时候通过super 传给父类(SelectorProvider 参数很关键);
 1.构造方法,支持各种参数的构造方法
 2.IO时间比例设置,调用内部的 NioEventLoop 来设置
 3.重建 selector,解决 epoll bug
 4.创建执行器,创建的是 NioEventLoop 实例,创建过程会用到SelectorProvider

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值