之前在第一篇文章里面对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函数的实现),然后线程不断的从任务队列里面取任务执行。