netty4.0.x源码分析—event

时间:2022-11-01 00:03:59

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

1、event总体结构图

event总体结构类图如下:

netty4.0.x源码分析—event
netty4.0.x源码分析—event


2、event关键类和接口分析

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

netty4.0.x源码分析—event

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,具体实现代码如下:

[java]   view plain copy netty4.0.x源码分析—event netty4.0.x源码分析—event
  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.             EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {  
  8.   
  9.         if (threadFactory == null) {  
  10.             throw new NullPointerException("threadFactory");  
  11.         }  
  12.   
  13.         this.parent = parent;  
  14.         this.addTaskWakesUp = addTaskWakesUp;  
  15.   
  16.         thread = threadFactory.newThread(new Runnable() {  
  17.             @Override  
  18.             public void run() {  
  19.                 boolean success = false;  
  20.                 updateLastExecutionTime();  
  21.                 try {  
  22.                     SingleThreadEventExecutor.this.run();  
  23.                     success = true;  
  24.                 } catch (Throwable t) {  
  25.                     logger.warn("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.                                 SingleThreadEventExecutor.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.                             terminationFuture.setSuccess(null);  
  61.                         }  
  62.                     }  
  63.                 }  
  64.             }  
  65.         });  
  66.   
  67.         taskQueue = newTaskQueue();  
  68.     }  
从上述代码可以看出,这个就是事件循环的具体实现代码了,大概意思是基于阻塞队列,从队列中取得待执行的任务执行,并且加入线程同步的考虑,开发者在使用时不需要考虑线程同步的问题。


SingleThreadEventLoop

它继承了SingleThreadEventExecutor并且实现了EventLoop接口,提供注册Channel到事件循环中的函数,以及获取EventLoopGroup和EventLoop的函数。


NioEventLoop

它继承SingleThreadEventLoop,具体参考如下代码:

[java]   view plain copy netty4.0.x源码分析—event netty4.0.x源码分析—event
  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.             SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();  
  32.   
  33.             Class<?> selectorImplClass =  
  34.                     Class.forName("sun.nio.ch.SelectorImpl"false, ClassLoader.getSystemClassLoader());  
  35.             selectorImplClass.isAssignableFrom(selector.getClass());  
  36.             Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");  
  37.             Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");  
  38.   
  39.             selectedKeysField.setAccessible(true);  
  40.             publicSelectedKeysField.setAccessible(true);  
  41.   
  42.             selectedKeysField.set(selector, selectedKeySet);  
  43.             publicSelectedKeysField.set(selector, selectedKeySet);  
  44.   
  45.             selectedKeys = selectedKeySet;  
  46.             logger.trace("Instrumented an optimized java.util.Set into: {}", selector);  
  47.         } catch (Throwable t) {  
  48.             selectedKeys = null;  
  49.             logger.trace("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

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类,具体实现代码如下

[java]   view plain copy netty4.0.x源码分析—event netty4.0.x源码分析—event
  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.         children = new SingleThreadEventExecutor[nThreads];  
  54.         for (int i = 0; i < nThreads; i ++) {  
  55.             boolean success = false;  
  56.             try {  
  57.                 children[i] = newChild(threadFactory, args);  
  58.                 success = 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.                     terminationFuture.setSuccess(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.         Set<EventExecutor> children = Collections.newSetFromMap(new LinkedHashMap<EventExecutor, Boolean>());  
  124.         Collections.addAll(children, 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.             ThreadFactory threadFactory, Object... args) throws Exception;  
  135.   
  136. }  
从代码中可以看出,它定义了一个EventExcutor类型的child数组,具体类型是SingleThreadEventExecutor。也就是说它实际上是多个SingleThreadEventExecutor,这个上面已经有过介绍了。

NioEventLoopGroup

它继承MultithreadEventLoopGroup,提供了几个额外的方法,如rebuildSelectors(重新生成selector),setIoRatio(设置IO处理的时间)等,重写newChild方法,具体代码如下:

[java]   view plain copy netty4.0.x源码分析—event netty4.0.x源码分析—event
  1. @Override  
  2.     protected EventExecutor newChild(  
  3.             ThreadFactory threadFactory, Object... args) 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事件的总体结构进行了分析,很多地方还不是很详细,具体细节还需要进一步分析代码。