Netty源码分析之EventLoop相关结构分析


  1. 先来一个继承图,仅仅观察EventExecutor体系的轮廓

  

2. Executor是JDK中提供的用于分离任务和执行的接口,ExecutorService在Executor基础上增加了一些方法加入了Future, ScheduledExecutorService提供了执行定时任务的方法,

AbstractExecutorService是一个基本实现, AutoClosable提供了close方法接口。

netty4、5的线程模型使得一个Channel上同一时间只会有一个线程进行IO操作,这样使用者便不需要考虑同步并发等多线程问题,大大简化了开发难度。


3. EventExecutorGroup

提供的方法有


shutdownGracefully,netty提供的优雅关闭的方法,通常用于EventLoopGroup的关闭,

重载的shutdownGracefully(long quietPeriod, long timeoutTimeUnit unit),

如果在quietPeriod期间没有任务提交,就关闭,如果有就接受这个任务并重新开始计算quietPeriod,timeout是executor被shutdown后的最大timeout时间,超过这个时间将会关闭。

next() 方法用于获得该EventExecutorGroup管理的下一个EventExecutor

children() 获得该EventExecutorGroup管理的所有子EventExecutor的unmodifiable set集合


4. EventExecutor



inEventLoop() 判断当前线程是否是EventLoop线程

parent() 获得管理它的EventLoopGroup


5. EventLoopGroup



next() 获得下一个EventLoop

register(Channel, ChannelPromise) 在管理的EventLoop集合中选择一个来注册该Channel, 传入的ChannelPromise参数是一个可写的Future,该方法返回的ChannelFuture即为该ChannelPromise

6. EventLoop



unwrap() 用来返回一个不是WrappedEventExecutor的EventLoop,WrappedEventExecutor是一个Marker Interface

asInvoker() 创建一个使用当前EventLoop来进行EventLoop处理的ChannelHandlerInvoker实现,

ChannelHandlerInvoker接口如下,包含了常用的IO触发方法



7 AbstractEventExecutorGroup 中实现了基本的方法,基本上都delegate给next()去执行, next留给了子类去实现。


8 MultithreadEventExecutorGroup 提供了多线程的EventExecutorGroup实现,其内部使用EventExecutor数组保存持有的children, next()方法根据

构造器传入的nEventExecutors判断使用的选择算法选择。

构造器的代码片段。

private MultithreadEventExecutorGroup(int nEventExecutors,
                                      Executor executor,
                                      boolean shutdownExecutor,
                                      Object... args) {
    if (nEventExecutors <= 0) {
        throw new IllegalArgumentException(
                String.format("nEventExecutors: %d (expected: > 0)", nEventExecutors));
    }

    if (executor == null) {
        executor = newDefaultExecutorService(nEventExecutors);
        shutdownExecutor = true;
    }

    children = new EventExecutor[nEventExecutors];
    if (isPowerOfTwo(children.length)) {
        chooser = new PowerOfTwoEventExecutorChooser();
    } else {
        chooser = new GenericEventExecutorChooser();
    }

    for (int i = 0; i < nEventExecutors; 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;
                    }
                }
            }
        }
    }

    final boolean shutdownExecutor0 = shutdownExecutor;
    final Executor executor0 = executor;
    final FutureListener terminationListener = new FutureListener() {
        @Override
        public void operationComplete(Future future) throws Exception {
            if (terminatedChildren.incrementAndGet() == children.length) {
                terminationFuture.setSuccess(null);
                if (shutdownExecutor0) {
                    // This cast is correct because shutdownExecutor0 is only try if
                    // executor0 is of type ExecutorService.
                    ((ExecutorService) executor0).shutdown();
                }
            }
        }
    };

    for (EventExecutor e: children) {
        e.terminationFuture().addListener(terminationListener);
    }

    Set childrenSet = new LinkedHashSet(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);
} 


9. MultithreadEventLoopGroup继承自MultithreadEventExecutorGroup,提供了默认的EventLoopThread数量的设置,默认为Runtime.availableProcessor() * 2

还有一些覆盖的方法


10. AbstractEventExecutor 继承自AbstractExecutorService, 提供了基本的方法实现。


11. AbstractScheduledEventExecutor 用来支持Schedule, 内部持有Queue>来管理维护任务队列

其中关键的代码部分是schedule


 ScheduledFuture schedule(final ScheduledFutureTask task) {
    if (inEventLoop()) {
        scheduledTaskQueue().add(task);
    } else {
        execute(new OneTimeTask() {
            @Override
            public void run() {
                scheduledTaskQueue().add(task);
            }
        });
    }

    return task;
}


判断如果当前线程是IO线程,则直接加到任务队列中,否则以Task的形式加入到队列中


11. NioEventLoop

于JDK nio 包相关的实现基本都在这里

持有

Selector selector;
private SelectedSelectionKeySet selectedKeys;

private final SelectorProvider provider;
 
selectorAutoRebuildThreshold用于设置JDK Epoll空轮询导致CPU占用100%的bug检测,检测到后重新创建 Selector并将之前的SelectionKey注册到新的Selector上.


@Override
protected Queue newTaskQueue() {
    // This event loop never calls takeTask()
 return PlatformDependent.newMpscQueue();
}

返回一个Multi Producer Single Consume 的多生产者单一消费者的队列

注册SelectableChannel的代码

 
public void register(final SelectableChannel ch, final int interestOps, final NioTask task) {
    
    // some param check
    try {
        ch.register(selector, interestOps, task);
 } catch (Exception e) {
        throw new EventLoopException("failed to register a channel", e);
 }
}



RebuildSelector的实现


public void rebuildSelector() {
    if (!inEventLoop()) {
        execute(new Runnable() {
            @Override
            public void run() {
                rebuildSelector();
            }
        });
        return;
    }

    final Selector oldSelector = selector;
    final Selector newSelector;

    if (oldSelector == null) {
        return;
    }

    try {
        newSelector = openSelector();
    } catch (Exception e) {
        logger.warn("Failed to create a new Selector.", e);
        return;
    }

    // Register all channels to the new Selector.
    int nChannels = 0;
    for (;;) {
        try {
            for (SelectionKey key: oldSelector.keys()) {
                Object a = key.attachment();
                try {
                    if (!key.isValid() || key.channel().keyFor(newSelector) != null) {
                        continue;
                    }

                    int interestOps = key.interestOps();
                    key.cancel();
                    SelectionKey newKey = key.channel().register(newSelector, interestOps, a);
                    if (a instanceof AbstractNioChannel) {
                        // Update SelectionKey
                        ((AbstractNioChannel) a).selectionKey = newKey;
                    }
                    nChannels ++;
                } catch (Exception e) {
                    logger.warn("Failed to re-register a Channel to the new Selector.", e);
                    if (a instanceof AbstractNioChannel) {
                        AbstractNioChannel ch = (AbstractNioChannel) a;
                        ch.unsafe().close(ch.unsafe().voidPromise());
                    } else {
                        @SuppressWarnings("unchecked")
                        NioTask task = (NioTask) a;
                        invokeChannelUnregistered(task, key, e);
                    }
                }
            }
        } catch (ConcurrentModificationException e) {
            // Probably due to concurrent modification of the key set.
            continue;
        }

        break;
    }

    selector = newSelector;

    try {
        // time to close the old selector as everything else is registered to the new one
        oldSelector.close();
    } catch (Throwable t) {
        if (logger.isWarnEnabled()) {
            logger.warn("Failed to close the old Selector.", t);
        }
    }

    logger.info("Migrated " + nChannels + " channel(s) to the new Selector.");
}


processSelectedKeysPlain
private void processSelectedKeysPlain(Set selectedKeys) {
    // check if the set is empty and if so just return to not create garbage by
    // creating a new Iterator every time even if there is nothing to process.
    // See https://github.com/netty/netty/issues/597
    if (selectedKeys.isEmpty()) {
        return;
    }

    Iterator i = selectedKeys.iterator();
    for (;;) {
        final SelectionKey k = i.next();
        final Object a = k.attachment();
        i.remove();

        if (a instanceof AbstractNioChannel) {
            processSelectedKey(k, (AbstractNioChannel) a);
        } else {
            @SuppressWarnings("unchecked")
            NioTask task = (NioTask) a;
            processSelectedKey(k, task);
        }

        if (!i.hasNext()) {
            break;
        }

        if (needsToSelectAgain) {
            selectAgain();
            selectedKeys = selector.selectedKeys();

            // Create the iterator again to avoid ConcurrentModificationException
            if (selectedKeys.isEmpty()) {
                break;
            } else {
                i = selectedKeys.iterator();
            }
        }
    }
}


 
 
 

你可能感兴趣的:(java,netty)