之前在第一篇文章里面对event的总体结构进行了简单的分析,没有结合代码理清流程,所以对于excutor和loop的具体执行机制还是很模糊,这篇文章针对代码从上至下进行分析,相信对理解excutor和loop到底是怎么关联的有所帮助。

       我们基于服务端常用的代码,EventLoopGroup bossGroup = new NioEventLoopGroup();为主线进行分析,这个函数就封装了线程的创建,以及loop和线程的关联等内容。

先看NioEventLoopGroup的源代码:


1. /**
2.  * {@link MultithreadEventLoopGroup} implementations which is used for NIO {@link Selector} based {@link Channel}s.
3.  */  
4. public class NioEventLoopGroup extends MultithreadEventLoopGroup {  
5.   
6. /**
7.      * Create a new instance using the default number of threads, the default {@link ThreadFactory} and
8.      * the {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
9.      */  
10. public NioEventLoopGroup() {  
11. this(0);  
12.     }  
13.   
14. /**
15.      * Create a new instance using the specified number of threads, {@link ThreadFactory} and the
16.      * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
17.      */  
18. public NioEventLoopGroup(int nThreads) {  
19. this(nThreads, null);  
20.     }  
21.   
22. /**
23.      * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the
24.      * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
25.      */  
26. public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {  
27. this(nThreads, threadFactory, SelectorProvider.provider());  
28.     }  
29.   
30. /**
31.      * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the given
32.      * {@link SelectorProvider}.
33.      */  
34. public NioEventLoopGroup(  
35. int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) {  
36. super(nThreads, threadFactory, selectorProvider);  
37.     }  
38.   
39. @Override  
40. protected EventExecutor newChild(  
41. throws Exception {  
42. return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]);  
43.     }  
44. }

从这个构造函数可以看出,实际上NioEventLoopGroup的构造就是调用了父类的构造函数完成的,那么就看父类的构造函数做了些什么,它的父类是MultithreadEventLoopGroup,下面是它的关键代码:


    1. /**
    2.  * Abstract base class for {@link EventLoopGroup} implementations that handles their tasks with multiple threads at
    3.  * the same time.
    4.  */  
    5. public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {  
    6.   
    7. private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);  
    8.   
    9. private static final int DEFAULT_EVENT_LOOP_THREADS;  
    10.   
    11. static {  
    12. 1, SystemPropertyUtil.getInt(  
    13. "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));  
    14.   
    15. if (logger.isDebugEnabled()) {  
    16. "-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);  
    17.         }  
    18.     }  
    19.   
    20. /**
    21.      * @see {@link MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, ThreadFactory, Object...)}
    22.      */  
    23. protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {  
    24. super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);  
    25.     }  
    26.   
    27. @Override  
    28. protected ThreadFactory newDefaultThreadFactory() {  
    29. return new DefaultThreadFactory(getClass(), Thread.MAX_PRIORITY);  
    30.     }  
    31.   
    32. @Override  
    33. public EventLoop next() {  
    34. return (EventLoop) super.next();  
    35.     }  
    36.   
    37. @Override  
    38. public ChannelFuture register(Channel channel) {  
    39. return next().register(channel);  
    40.     }  
    41.   
    42. @Override  
    43. public ChannelFuture register(Channel channel, ChannelPromise promise) {  
    44. return next().register(channel, promise);  
    45.     }  
    46. }


    从上面的代码可以看出,若给定的线程数为0,则将默认的事件循环线程数作为参数继续调用父类的构造函数,继续看它的父类MultithreadEventExecutorGroup的定义,关键代码如下:


    1. /**
    2.  * Abstract base class for {@link EventExecutorGroup} implementations that handles their tasks with multiple threads at
    3.  * the same time.
    4.  */  
    5. public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {  
    6.   
    7. private final EventExecutor[] children;  
    8. private final AtomicInteger childIndex = new AtomicInteger();  
    9. private final AtomicInteger terminatedChildren = new AtomicInteger();  
    10. private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);  
    11.   
    12. /**
    13.      * Create a new instance.
    14.      *
    15.      * @param nThreads          the number of threads that will be used by this instance.
    16.      * @param threadFactory     the ThreadFactory to use, or {@code null} if the default should be used.
    17.      * @param args              arguments which will passed to each {@link #newChild(ThreadFactory, Object...)} call
    18.      */  
    19. protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) {  
    20. if (nThreads <= 0) {  
    21. throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));  
    22.         }  
    23.   
    24. if (threadFactory == null) {  
    25.             threadFactory = newDefaultThreadFactory();  
    26.         }  
    27.   
    28. new SingleThreadEventExecutor[nThreads];  
    29. for (int i = 0; i < nThreads; i ++) {  
    30. boolean success = false;  
    31. try {  
    32.                 children[i] = newChild(threadFactory, args);  
    33. true;  
    34. catch (Exception e) {  
    35. // TODO: Think about if this is a good exception type  
    36. throw new IllegalStateException("failed to create a child event loop", e);  
    37. finally {  
    38. if (!success) {  
    39. for (int j = 0; j < i; j ++) {  
    40.                         children[j].shutdownGracefully();  
    41.                     }  
    42.   
    43. for (int j = 0; j < i; j ++) {  
    44.                         EventExecutor e = children[j];  
    45. try {  
    46. while (!e.isTerminated()) {  
    47.                                 e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);  
    48.                             }  
    49. catch (InterruptedException interrupted) {  
    50.                             Thread.currentThread().interrupt();  
    51. break;  
    52.                         }  
    53.                     }  
    54.                 }  
    55.             }  
    56.         }  
    57.   
    58. final FutureListener<Object> terminationListener = new FutureListener<Object>() {  
    59. @Override  
    60. public void operationComplete(Future<Object> future) throws Exception {  
    61. if (terminatedChildren.incrementAndGet() == children.length) {  
    62. null);  
    63.                 }  
    64.             }  
    65.         };  
    66.   
    67. for (EventExecutor e: children) {  
    68.             e.terminationFuture().addListener(terminationListener);  
    69.         }  
    70.     }  
    71.   
    72. protected ThreadFactory newDefaultThreadFactory() {  
    73. return new DefaultThreadFactory(getClass());  
    74.     }  
    75.   
    76. @Override  
    77. public EventExecutor next() {  
    78. return children[Math.abs(childIndex.getAndIncrement() % children.length)];  
    79.     }  
    80.   
    81. @Override  
    82. public Iterator<EventExecutor> iterator() {  
    83. return children().iterator();  
    84.     }  
    85.   
    86. /**
    87.      * Return the number of {@link EventExecutor} this implementation uses. This number is the maps
    88.      * 1:1 to the threads it use.
    89.      */  
    90. public final int executorCount() {  
    91. return children.length;  
    92.     }  
    93.   
    94. /**
    95.      * Return a safe-copy of all of the children of this group.
    96.      */  
    97. protected Set<EventExecutor> children() {  
    98. new LinkedHashMap<EventExecutor, Boolean>());  
    99. this.children);  
    100. return children;  
    101.     }  
    102.   
    103. /**
    104.      * Create a new EventExecutor which will later then accessible via the {@link #next()}  method. This method will be
    105.      * called for each thread that will serve this {@link MultithreadEventExecutorGroup}.
    106.      *
    107.      */  
    108. protected abstract EventExecutor newChild(  
    109. throws Exception;  
    110.   
    111. @Override  
    112. public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {  
    113. for (EventExecutor l: children) {  
    114.             l.shutdownGracefully(quietPeriod, timeout, unit);  
    115.         }  
    116. return terminationFuture();  
    117.     }  
    118. }


    重点是它的构造函数,我们看出它里面实际上还是由多个SingleThreadEventExecutor构造的,调用了newChild函数为每个EventExecutor赋值,继续看newChild的实现,我们是基于NioEventLoopGroup进行分析的所以,我们直接看它的newChild实现:


      1. @Override  
      2. protected EventExecutor newChild(  
      3. throws Exception {  
      4. return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]);  
      5. }


      上面的代码进而调用了new NioEventLoop函数构造EventExecutor,下面是NioEventLoop构造函数

        1. NioEventLoop(NioEventLoopGroup parent, ThreadFactory threadFactory, SelectorProvider selectorProvider) {  
        2. super(parent, threadFactory, false);  
        3. if (selectorProvider == null) {  
        4. throw new NullPointerException("selectorProvider");  
        5.     }  
        6.     provider = selectorProvider;  
        7.     selector = openSelector();  
        8. }


        从这个代码,我们可以发现EventExcutor->EventLoop->Selector,三种的对应关系。继续看它的父类SingleThreadEventLoop的关键代码

        1. /**
        2.  * Abstract base class for {@link EventLoop}'s that execute all its submitted tasks in a single thread.
        3.  *
        4.  */  
        5. public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {  
        6.   
        7. /**
        8.      * @see {@link SingleThreadEventExecutor#SingleThreadEventExecutor(EventExecutorGroup, ThreadFactory, boolean)}
        9.      */  
        10. protected SingleThreadEventLoop(EventLoopGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {  
        11. super(parent, threadFactory, addTaskWakesUp);  
        12.     }  
        13.   
        14. @Override  
        15. public EventLoopGroup parent() {  
        16. return (EventLoopGroup) super.parent();  
        17.     }  
        18.   
        19. @Override  
        20. public EventLoop next() {  
        21. return (EventLoop) super.next();  
        22.     }  
        23.   
        24. @Override  
        25. public ChannelFuture register(Channel channel) {  
        26. return register(channel, channel.newPromise());  
        27.     }  
        28.   
        29. @Override  
        30. public ChannelFuture register(final Channel channel, final ChannelPromise promise) {  
        31. if (channel == null) {  
        32. throw new NullPointerException("channel");  
        33.         }  
        34. if (promise == null) {  
        35. throw new NullPointerException("promise");  
        36.         }  
        37.   
        38. this, promise);  
        39. return promise;  
        40.     }  
        41. }


        它的构造函数还是调用了父类的构造函数,继续看它的父类SingleThreadEventExecutor的关键代码,

        这个类非常重要,有时间需要再仔细看看,这里我们可以清晰的看到它生成了一个线程,并且构造了一个任务队列。并且它还重写了excute方法,将线程任务都添加到任务队列,run方法则不断的从任务队列里面取任务执行,从子类的run方法可以清晰的看到这点。

        1. /**
        2.  * Create a new instance
        3.  *
        4.  * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it
        5.  * @param threadFactory     the {@link ThreadFactory} which will be used for the used {@link Thread}
        6.  * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the
        7.  *                          executor thread
        8.  */  
        9. protected SingleThreadEventExecutor(  
        10. boolean addTaskWakesUp) {  
        11.   
        12. if (threadFactory == null) {  
        13. throw new NullPointerException("threadFactory");  
        14.     }  
        15.   
        16. this.parent = parent;  
        17. this.addTaskWakesUp = addTaskWakesUp;  
        18.   
        19. new Runnable() {  
        20. @Override  
        21. public void run() {  
        22. boolean success = false;  
        23.             updateLastExecutionTime();  
        24. try {  
        25. this.run();  
        26. true;  
        27. catch (Throwable t) {  
        28. "Unexpected exception from an event executor: ", t);  
        29. finally {  
        30. if (state < ST_SHUTTING_DOWN) {  
        31.                     state = ST_SHUTTING_DOWN;  
        32.                 }  
        33.   
        34. // Check if confirmShutdown() was called at the end of the loop.  
        35. if (success && gracefulShutdownStartTime == 0) {  
        36.                     logger.error(  
        37. "Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +  
        38. class.getSimpleName() + ".confirmShutdown() must be called " +  
        39. "before run() implementation terminates.");  
        40.                 }  
        41.   
        42. try {  
        43. // Run all remaining tasks and shutdown hooks.  
        44. for (;;) {  
        45. if (confirmShutdown()) {  
        46. break;  
        47.                         }  
        48.                     }  
        49. finally {  
        50. try {  
        51.                         cleanup();  
        52. finally {  
        53. synchronized (stateLock) {  
        54.                             state = ST_TERMINATED;  
        55.                         }  
        56.                         threadLock.release();  
        57. if (!taskQueue.isEmpty()) {  
        58.                             logger.warn(  
        59. "An event executor terminated with " +  
        60. "non-empty task queue (" + taskQueue.size() + ')');  
        61.                         }  
        62.   
        63. null);  
        64.                     }  
        65.                 }  
        66.             }  
        67.         }  
        68.     });  
        69.   
        70.     taskQueue = newTaskQueue();  
        71. }<pre name="code" class="java">    @Override  
        72. public void execute(Runnable task) {  
        73. if (task == null) {  
        74. throw new NullPointerException("task");  
        75.     }  
        76.   
        77. boolean inEventLoop = inEventLoop();  
        78. if (inEventLoop) {  
        79.         addTask(task);  
        80. else {  
        81.         startThread();  
        82.         addTask(task);  
        83. if (isShutdown() && removeTask(task)) {  
        84.             reject();  
        85.         }  
        86.     }  
        87.   
        88. if (!addTaskWakesUp) {  
        89.         wakeup(inEventLoop);  
        90.     }  
        91. }


        1. @Override  
        2. protected void run() {  
        3. for (;;) {  
        4. false);  
        5. try {  
        6. if (hasTasks()) {  
        7.                 selectNow();  
        8. else {  
        9.                 select();  
        10.   
        11. // 'wakenUp.compareAndSet(false, true)' is always evaluated  
        12. // before calling 'selector.wakeup()' to reduce the wake-up  
        13. // overhead. (Selector.wakeup() is an expensive operation.)  
        14. //  
        15. // However, there is a race condition in this approach.  
        16. // The race condition is triggered when 'wakenUp' is set to  
        17. // true too early.  
        18. //  
        19. // 'wakenUp' is set to true too early if:  
        20. // 1) Selector is waken up between 'wakenUp.set(false)' and  
        21. //    'selector.select(...)'. (BAD)  
        22. // 2) Selector is waken up between 'selector.select(...)' and  
        23. //    'if (wakenUp.get()) { ... }'. (OK)  
        24. //  
        25. // In the first case, 'wakenUp' is set to true and the  
        26. // following 'selector.select(...)' will wake up immediately.  
        27. // Until 'wakenUp' is set to false again in the next round,  
        28. // 'wakenUp.compareAndSet(false, true)' will fail, and therefore  
        29. // any attempt to wake up the Selector will fail, too, causing  
        30. // the following 'selector.select(...)' call to block  
        31. // unnecessarily.  
        32. //  
        33. // To fix this problem, we wake up the selector again if wakenUp  
        34. // is true immediately after selector.select(...).  
        35. // It is inefficient in that it wakes up the selector for both  
        36. // the first case (BAD - wake-up required) and the second case  
        37. // (OK - no wake-up required).  
        38.   
        39. if (wakenUp.get()) {  
        40.                     selector.wakeup();  
        41.                 }  
        42.             }  
        43.   
        44. 0;  
        45.   
        46. final long ioStartTime = System.nanoTime();  
        47. false;  
        48. if (selectedKeys != null) {  
        49.                 processSelectedKeysOptimized(selectedKeys.flip());  
        50. else {  
        51.                 processSelectedKeysPlain(selector.selectedKeys());  
        52.             }  
        53. final long ioTime = System.nanoTime() - ioStartTime;  
        54.   
        55. final int ioRatio = this.ioRatio;  
        56. 100 - ioRatio) / ioRatio);  
        57.   
        58. if (isShuttingDown()) {  
        59.                 closeAll();  
        60. if (confirmShutdown()) {  
        61. break;  
        62.                 }  
        63.             }  
        64. catch (Throwable t) {  
        65. "Unexpected exception in the selector loop.", t);  
        66.   
        67. // Prevent possible consecutive immediate failures that lead to  
        68. // excessive CPU consumption.  
        69. try {  
        70. 1000);  
        71. catch (InterruptedException e) {  
        72. // Ignore.  
        73.             }  
        74.         }  
        75.     }  
        76. }

        上面的代码又调用了父类定义的runAllTasks函数,下面是SingleThreadEventExecutor中的定义:


          1. /**
          2.  * Poll all tasks from the task queue and run them via {@link Runnable#run()} method.  This method stops running
          3.  * the tasks in the task queue and returns if it ran longer than {@code timeoutNanos}.
          4.  */  
          5. protected boolean runAllTasks(long timeoutNanos) {  
          6.     fetchFromDelayedQueue();  
          7.     Runnable task = pollTask();  
          8. if (task == null) {  
          9. return false;  
          10.     }  
          11.   
          12. final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;  
          13. long runTasks = 0;  
          14. long lastExecutionTime;  
          15. for (;;) {  
          16. try {  
          17.             task.run();  
          18. catch (Throwable t) {  
          19. "A task raised an exception.", t);  
          20.         }  
          21.   
          22.         runTasks ++;  
          23.   
          24. // Check timeout every 64 tasks because nanoTime() is relatively expensive.  
          25. // XXX: Hard-coded value - will make it configurable if it is really a problem.  
          26. if ((runTasks & 0x3F) == 0) {  
          27.             lastExecutionTime = ScheduledFutureTask.nanoTime();  
          28. if (lastExecutionTime >= deadline) {  
          29. break;  
          30.             }  
          31.         }  
          32.   
          33.         task = pollTask();  
          34. if (task == null) {  
          35.             lastExecutionTime = ScheduledFutureTask.nanoTime();  
          36. break;  
          37.         }  
          38.     }  
          39.   
          40. this.lastExecutionTime = lastExecutionTime;  
          41. return true;  
          42. }


          从这里,我们可以看到任务队列是如何取任务执行了。

          总结:

          通过上面的分析,我们基本上了解了eventloop和excutor,以及线程之间的关系了,其实netty就是实现了自己的一个线程池,来执行线程任务。大概的流程就是在eventloop的selector中注册channel,然后channel的事件处理都以线程任务的形式执行,并且先放入任务队列中(因为它重写了executor方法,在SingleThreadEventExecutor中我们可以看到重写的executor函数的实现),然后线程不断的从任务队列里面取任务执行。