Netty4 3_EventExecutorGroup

其实,我觉得netty的源码还是有点恶心的,特别是注解,很多相应的方法和属性的都没有写上注释,只有在抽象接口中有方法的说明,而子类的相关细节却被完完全全的忽略,笔者这样增加了开发人员的netty的研读,也加大理解netty架构的难度


先讲一下EventExecutorGroup的功能吧,EventExecutorGroup看到event、executor、group就知道他是一个与线程、事件以及群组的功能了,也就是他根据通道相应的事件对通道进行处理,而这个处理也有可能是多个线程的多线程处理


我们先来看一下EventExecutorGroup的类的结构吧

Netty4 3_EventExecutorGroup_第1张图片


首先,我们来看第(1)部分的基本方法

EventExecurotGroup

Netty4 3_EventExecutorGroup_第2张图片


MultithreadEventLoopGroup

Netty4 3_EventExecutorGroup_第3张图片


可见由于继承了ScheduledExecutorService和Iterator,EventExecutorGroup具备了一些线程和iterator最基本的方法,而MultithreadEventLoopGroup底层有多个EventExecutor数组进行处理而已


接着我们来看一下第(3)部分基本方法

Netty4 3_EventExecutorGroup_第4张图片 


EventExecutor是一个特殊的EventExecutorGroup带来一些便捷的方法(inEventLoop()、inEventLoop(Thread))去检查一个线程是否在一个事件循环中执行。 而且它也扩展了EventExecutorGroup访问方法允许一个通用的方法。


接下来我们再看第(2)部分


可见EventLoopGroup其实就是一个真正为Channel处理的相关的相关子类,具备有将channel注册到EventExecutorGroup的selector的功能


所以第(2)部分才是基于nio的Channel编程的netty实现的功能所在了,而其他两个部分更多的像是提供一种中间辅助类的功能,以及相应方法实现的封装了


以下过程可能会有点复杂,但记得对照类的结构图来看,还是很容易理解的


接下来,我们从netty第一篇文章的相应片段开始




我们再来看一以下NioEventLoopGroup(他也是一个EventLoopGroup)中的处理

Netty4 3_EventExecutorGroup_第5张图片



再看基类MultithreadEventLoopGroup的处理

Netty4 3_EventExecutorGroup_第6张图片

可见它是根据当前cpu处理器个数的两倍来充当线程数(此时nThreads为 0)



我们再看基类 MultithreadEventExecutorGroup怎么处理

Netty4 3_EventExecutorGroup_第7张图片



再看newChild的本例的实现类

Netty4 3_EventExecutorGroup_第8张图片


由此可见child数组的每个元素其实是一个NioEventLoop对象


Netty4 3_EventExecutorGroup_第9张图片

再看super(parent,threadfactory,selectorProvider)在基类的代码

Netty4 3_EventExecutorGroup_第10张图片


所以每个child数组元素的线程就在此处创建:

thread = threadFactory.newThread(new Runnable()

同时也创建了线程的任务队列,是一个LinkedBlockingQueue结构。


再看SingleThreadEventExecutor.this.run()在本例中是NioEventLoop

    @Override
    protected void run() {
        for (;;) {
            oldWakenUp = wakenUp.getAndSet(false);
            try {
                if (hasTasks()) {   //如果有任务,马上进行选择(非阻塞)
                    selectNow();
                } else {
                    select();

                    // 'wakenUp.compareAndSet(false, true)' is always evaluated
                    // before calling 'selector.wakeup()' to reduce the wake-up
                    // overhead. (Selector.wakeup() is an expensive operation.)
                    //
                    // However, there is a race condition in this approach.
                    // The race condition is triggered when 'wakenUp' is set to
                    // true too early.
                    //
                    // 'wakenUp' is set to true too early if:
                    // 1) Selector is waken up between 'wakenUp.set(false)' and
                    //    'selector.select(...)'. (BAD)
                    // 2) Selector is waken up between 'selector.select(...)' and
                    //    'if (wakenUp.get()) { ... }'. (OK)
                    //
                    // In the first case, 'wakenUp' is set to true and the
                    // following 'selector.select(...)' will wake up immediately.
                    // Until 'wakenUp' is set to false again in the next round,
                    // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
                    // any attempt to wake up the Selector will fail, too, causing
                    // the following 'selector.select(...)' call to block
                    // unnecessarily.
                    //
                    // To fix this problem, we wake up the selector again if wakenUp
                    // is true immediately after selector.select(...).
                    // It is inefficient in that it wakes up the selector for both
                    // the first case (BAD - wake-up required) and the second case
                    // (OK - no wake-up required).

                    if (wakenUp.get()) {
                        selector.wakeup();
                    }
                }

                cancelledKeys = 0;

                final long ioStartTime = System.nanoTime();
                needsToSelectAgain = false;
                if (selectedKeys != null) {
                    processSelectedKeysOptimized(selectedKeys.flip());
                } else {
                    processSelectedKeysPlain(selector.selectedKeys());
                }
                final long ioTime = System.nanoTime() - ioStartTime;

                final int ioRatio = this.ioRatio;
                runAllTasks(ioTime * (100 - ioRatio) / ioRatio);

                if (isShuttingDown()) {
                    closeAll();
                    if (confirmShutdown()) {
                        break;
                    }
                }
            } catch (Throwable t) {
                logger.warn("Unexpected exception in the selector loop.", t);

                // Prevent possible consecutive immediate failures that lead to
                // excessive CPU consumption.
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // Ignore.
                }
            }
        }
    }
至此,NioEventLoopGroup创建完毕了


总结:

EventLoopGroup bossGroup = new NioEventLoopGroup()发生了以下事情:

1、 为NioEventLoopGroup创建数量为:处理器个数 x 2的,类型为NioEventLoop的实例。每个NioEventLoop实例 都持有一个线程,以及一个类型为LinkedBlockingQueue的任务队列

2、线程的执行逻辑由NioEventLoop实现

3、每个NioEventLoop实例都持有一个selector,并对selector进行优化。




你可能感兴趣的:(Java,Netty)