备注:本文的分析基于netty4.0.9final版本
1、event总体结构图
event总体结构类图如下:
2、event关键类和接口分析
1)基于NioEventLoop对关键类和接口进行分析,下面是它的关系图:
EventExecutor
相当于只有一个EventExcutor的EventExecutorGroup,它的next方法返回的是自己的引用,并且它还提供了方法判断线程是否在eventloop中执行,它是一个任务执行器。
EventExecutorGroup它继承了ScheduledExecutorService, Iterable<EventExecutor>,可以被看作是任务的调度执行器和EventExecutor容器,主要是定义了一些submit和schedule方法(用于线程的执行),以及next方法(返回一个EventExecutor实例)。
EventLoopGroup
它继承EventExecutorGroup,额外提供3个方法,一个next返回空闲的EventLoop,register方法注册Channel到EventLoop中。
EventLoop接口同时继承了EventExecutor和EventLoopGroup,因此它既是一个执行器,又是容器,提供一个parent方法,返回它所属的EventLoopGroup。其实它相当于是只有一个EventLoop的EventLoopGroup。
AbstractEventExecutor
它继承AbstractExecutorService并且实现EventExecutor接口,提供submit,schedule,已经next等方法。
SingleThreadEventExecutor
它继承AbstractEventExecutor,具体实现代码如下:
1. private final EventExecutorGroup parent;
2. private final Queue<Runnable> taskQueue;
3. final Queue<ScheduledFutureTask<?>> delayedTaskQueue = new PriorityQueue<ScheduledFutureTask<?>>();
4.
5. private final Thread thread;
6. <pre name="code" class="java"> protected SingleThreadEventExecutor(
7. boolean addTaskWakesUp) {
8.
9. if (threadFactory == null) {
10. throw new NullPointerException("threadFactory");
11. }
12.
13. this.parent = parent;
14. this.addTaskWakesUp = addTaskWakesUp;
15.
16. new Runnable() {
17. @Override
18. public void run() {
19. boolean success = false;
20. updateLastExecutionTime();
21. try {
22. this.run();
23. true;
24. catch (Throwable t) {
25. "Unexpected exception from an event executor: ", t);
26. finally {
27. if (state < ST_SHUTTING_DOWN) {
28. state = ST_SHUTTING_DOWN;
29. }
30.
31. // Check if confirmShutdown() was called at the end of the loop.
32. if (success && gracefulShutdownStartTime == 0) {
33. logger.error(
34. "Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
35. class.getSimpleName() + ".confirmShutdown() must be called " +
36. "before run() implementation terminates.");
37. }
38.
39. try {
40. // Run all remaining tasks and shutdown hooks.
41. for (;;) {
42. if (confirmShutdown()) {
43. break;
44. }
45. }
46. finally {
47. try {
48. cleanup();
49. finally {
50. synchronized (stateLock) {
51. state = ST_TERMINATED;
52. }
53. threadLock.release();
54. if (!taskQueue.isEmpty()) {
55. logger.warn(
56. "An event executor terminated with " +
57. "non-empty task queue (" + taskQueue.size() + ')');
58. }
59.
60. null);
61. }
62. }
63. }
64. }
65. });
66.
67. taskQueue = newTaskQueue();
68. }
从上述代码可以看出,这个就是事件循环的具体实现代码了,大概意思是基于阻塞队列,从队列中取得待执行的任务执行,并且加入线程同步的考虑,开发者在使用时不需要考虑线程同步的问题。
SingleThreadEventLoop
它继承了SingleThreadEventExecutor并且实现了EventLoop接口,提供注册Channel到事件循环中的函数,以及获取EventLoopGroup和EventLoop的函数。
NioEventLoop
它继承SingleThreadEventLoop,具体参考如下代码:
1. /**
2. * The NIO {@link Selector}.
3. */
4. Selector selector;
5. private SelectedSelectionKeySet selectedKeys;
6.
7. private final SelectorProvider provider;
8.
9. <pre name="code" class="java"> NioEventLoop(NioEventLoopGroup parent, ThreadFactory threadFactory, SelectorProvider selectorProvider) {
10. super(parent, threadFactory, false);
11. if (selectorProvider == null) {
12. throw new NullPointerException("selectorProvider");
13. }
14. provider = selectorProvider;
15. selector = openSelector();
16. }
17.
18. private Selector openSelector() {
19. final Selector selector;
20. try {
21. selector = provider.openSelector();
22. catch (IOException e) {
23. throw new ChannelException("failed to open a new selector", e);
24. }
25.
26. if (DISABLE_KEYSET_OPTIMIZATION) {
27. return selector;
28. }
29.
30. try {
31. new SelectedSelectionKeySet();
32.
33. Class<?> selectorImplClass =
34. "sun.nio.ch.SelectorImpl", false, ClassLoader.getSystemClassLoader());
35. selectorImplClass.isAssignableFrom(selector.getClass());
36. "selectedKeys");
37. "publicSelectedKeys");
38.
39. true);
40. true);
41.
42. selectedKeysField.set(selector, selectedKeySet);
43. publicSelectedKeysField.set(selector, selectedKeySet);
44.
45. selectedKeys = selectedKeySet;
46. "Instrumented an optimized java.util.Set into: {}", selector);
47. catch (Throwable t) {
48. null;
49. "Failed to instrument an optimized java.util.Set into: {}", selector, t);
50. }
51.
52. return selector;
53. }
从这几个数据属性和代码可以看出这时netty开始调用JDK的Socket函数,包括我们熟悉的selector和key。也就是说真正调用底层socket的地方是在NioEventLoop中。
2)基于NioEventLoopGroup对关键类和接口进行分析,下面是它的关系图:
EventExecutorGroup
它继承了ScheduledExecutorService, Iterable<EventExecutor>,可以被看作是任务的调度执行器和EventExecutor容器
主要是定义了一些submit和schedule方法(用于线程的执行),以及next方法(返回一个EventExecutor实例)。
EventExecutor是一个特殊的EventExecutorGroup,它的next方法返回的是自己的引用,并且它还提供了方法判断线程是否在eventloop中执行,它是一个任务执行器。
EventLoopGroup
它继承EventExecutorGroup,提供3个方法,一个next返回空闲的EventLoop,register方法注册Channel到EventLoop中。
EventLoop接口同时继承了EventExecutor和EventLoopGroup,因此它既是一个执行器,又是容器,提供一个parent方法,返回它所属的EventLoopGroup。
AbstractEventExecutorGroup
它实现EventExecutorGroup接口的submit和schedule方法。
MultithreadEventExecutorGroup
它继承AbstractEventExecutorGroup类,具体实现代码如下
1. /*
2. * Copyright 2012 The Netty Project
3. *
4. * The Netty Project licenses this file to you under the Apache License,
5. * version 2.0 (the "License"); you may not use this file except in compliance
6. * with the License. You may obtain a copy of the License at:
7. *
8. * http://www.apache.org/licenses/LICENSE-2.0
9. *
10. * Unless required by applicable law or agreed to in writing, software
11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13. * License for the specific language governing permissions and limitations
14. * under the License.
15. */
16. package io.netty.util.concurrent;
17.
18. import java.util.Collections;
19. import java.util.Iterator;
20. import java.util.LinkedHashMap;
21. import java.util.Set;
22. import java.util.concurrent.ThreadFactory;
23. import java.util.concurrent.TimeUnit;
24. import java.util.concurrent.atomic.AtomicInteger;
25.
26. /**
27. * Abstract base class for {@link EventExecutorGroup} implementations that handles their tasks with multiple threads at
28. * the same time.
29. */
30. public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
31.
32. private final EventExecutor[] children;
33. private final AtomicInteger childIndex = new AtomicInteger();
34. private final AtomicInteger terminatedChildren = new AtomicInteger();
35. private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
36.
37. /**
38. * Create a new instance.
39. *
40. * @param nThreads the number of threads that will be used by this instance.
41. * @param threadFactory the ThreadFactory to use, or {@code null} if the default should be used.
42. * @param args arguments which will passed to each {@link #newChild(ThreadFactory, Object...)} call
43. */
44. protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
45. if (nThreads <= 0) {
46. throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
47. }
48.
49. if (threadFactory == null) {
50. threadFactory = newDefaultThreadFactory();
51. }
52.
53. new SingleThreadEventExecutor[nThreads];
54. for (int i = 0; i < nThreads; i ++) {
55. boolean success = false;
56. try {
57. children[i] = newChild(threadFactory, args);
58. true;
59. catch (Exception e) {
60. // TODO: Think about if this is a good exception type
61. throw new IllegalStateException("failed to create a child event loop", e);
62. finally {
63. if (!success) {
64. for (int j = 0; j < i; j ++) {
65. children[j].shutdownGracefully();
66. }
67.
68. for (int j = 0; j < i; j ++) {
69. EventExecutor e = children[j];
70. try {
71. while (!e.isTerminated()) {
72. e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
73. }
74. catch (InterruptedException interrupted) {
75. Thread.currentThread().interrupt();
76. break;
77. }
78. }
79. }
80. }
81. }
82.
83. final FutureListener<Object> terminationListener = new FutureListener<Object>() {
84. @Override
85. public void operationComplete(Future<Object> future) throws Exception {
86. if (terminatedChildren.incrementAndGet() == children.length) {
87. null);
88. }
89. }
90. };
91.
92. for (EventExecutor e: children) {
93. e.terminationFuture().addListener(terminationListener);
94. }
95. }
96.
97. protected ThreadFactory newDefaultThreadFactory() {
98. return new DefaultThreadFactory(getClass());
99. }
100.
101. @Override
102. public EventExecutor next() {
103. return children[Math.abs(childIndex.getAndIncrement() % children.length)];
104. }
105.
106. @Override
107. public Iterator<EventExecutor> iterator() {
108. return children().iterator();
109. }
110.
111. /**
112. * Return the number of {@link EventExecutor} this implementation uses. This number is the maps
113. * 1:1 to the threads it use.
114. */
115. public final int executorCount() {
116. return children.length;
117. }
118.
119. /**
120. * Return a safe-copy of all of the children of this group.
121. */
122. protected Set<EventExecutor> children() {
123. new LinkedHashMap<EventExecutor, Boolean>());
124. this.children);
125. return children;
126. }
127.
128. /**
129. * Create a new EventExecutor which will later then accessible via the {@link #next()} method. This method will be
130. * called for each thread that will serve this {@link MultithreadEventExecutorGroup}.
131. *
132. */
133. protected abstract EventExecutor newChild(
134. throws Exception;
135.
136. }
从代码中可以看出,它定义了一个EventExcutor类型的child数组,具体类型是SingleThreadEventExecutor。也就是说它实际上是多个SingleThreadEventExecutor,这个上面已经有过介绍了。
NioEventLoopGroup
它继承MultithreadEventLoopGroup,提供了几个额外的方法,如rebuildSelectors(重新生成selector),setIoRatio(设置IO处理的时间)等,重写newChild方法,具体代码如下:
1. @Override
2. protected EventExecutor newChild(
3. throws Exception {
4. return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]);
5. }
实际上就是返回一个NioEventLoop对象,参考NioEventLoop的分析。
3、总结
其实整个event就是围绕着Loop和Excutor进行的,LoopGroup和ExcutorGroup相当于Loop和Excutor的容器,Group中包括了多个Loop和多个Excutor,所以单个Loop和Excutor也可以理解为一个Group,但其中只有一个Loop和Excutor。Loop用于事件循环,Excutor用于任务的提交调度执行。
备注:这里简单的对event事件的总体结构进行了分析,很多地方还不是很详细,具体细节还需要进一步分析代码。