备注:本文的分析基于netty4.0.9final版本

1、event总体结构图

event总体结构类图如下:




netty4.0.x源码分析—event_sed



netty4.0.x源码分析—event_java_02



2、event关键类和接口分析

1)基于NioEventLoop对关键类和接口进行分析,下面是它的关系图:

netty4.0.x源码分析—event_java_03

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对关键类和接口进行分析,下面是它的关系图:

netty4.0.x源码分析—event_ide_04

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事件的总体结构进行了分析,很多地方还不是很详细,具体细节还需要进一步分析代码。