关闭

netty4.0.x源码分析—executor和loop

465人阅读 评论(0) 收藏 举报
分类:

  之前在第一篇文章里面对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.             ThreadFactory threadFactory, Object... args) 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.         DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(  
  13.                 "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));  
  14.   
  15.         if (logger.isDebugEnabled()) {  
  16.             logger.debug("-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.         children = new SingleThreadEventExecutor[nThreads];  
  29.         for (int i = 0; i < nThreads; i ++) {  
  30.             boolean success = false;  
  31.             try {  
  32.                 children[i] = newChild(threadFactory, args);  
  33.                 success = 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.                     terminationFuture.setSuccess(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.         Set<EventExecutor> children = Collections.newSetFromMap(new LinkedHashMap<EventExecutor, Boolean>());  
  99.         Collections.addAll(children, 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.             ThreadFactory threadFactory, Object... args) 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.         ThreadFactory threadFactory, Object... args) 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.         channel.unsafe().register(this, promise);  
  39.         return promise;  
  40.     }  
  41. }  
它的构造函数还是调用了父类的构造函数,继续看它的父类SingleThreadEventExecutor的关键代码,
  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.         EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {  
  11.   
  12.     if (threadFactory == null) {  
  13.         throw new NullPointerException("threadFactory");  
  14.     }  
  15.   
  16.     this.parent = parent;  
  17.     this.addTaskWakesUp = addTaskWakesUp;  
  18.   
  19.     thread = threadFactory.newThread(new Runnable() {  
  20.         @Override  
  21.         public void run() {  
  22.             boolean success = false;  
  23.             updateLastExecutionTime();  
  24.             try {  
  25.                 SingleThreadEventExecutor.this.run();  
  26.                 success = true;  
  27.             } catch (Throwable t) {  
  28.                 logger.warn("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.                             SingleThreadEventExecutor.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.                         terminationFuture.setSuccess(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. }  

这个类非常重要,有时间需要再仔细看看,这里我们可以清晰的看到它生成了一个线程,并且构造了一个任务队列。并且它还重写了excute方法,将线程任务都添加到任务队列,run方法则不断的从任务队列里面取任务执行,从子类的run方法可以清晰的看到这点。
  1. @Override  
  2. protected void run() {  
  3.     for (;;) {  
  4.         oldWakenUp = wakenUp.getAndSet(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.             cancelledKeys = 0;  
  45.   
  46.             final long ioStartTime = System.nanoTime();  
  47.             needsToSelectAgain = 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.             runAllTasks(ioTime * (100 - ioRatio) / ioRatio);  
  57.   
  58.             if (isShuttingDown()) {  
  59.                 closeAll();  
  60.                 if (confirmShutdown()) {  
  61.                     break;  
  62.                 }  
  63.             }  
  64.         } catch (Throwable t) {  
  65.             logger.warn("Unexpected exception in the selector loop.", t);  
  66.   
  67.             // Prevent possible consecutive immediate failures that lead to  
  68.             // excessive CPU consumption.  
  69.             try {  
  70.                 Thread.sleep(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.             logger.warn("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函数的实现),然后线程不断的从任务队列里面取任务执行。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1420214次
    • 积分:21808
    • 等级:
    • 排名:第332名
    • 原创:470篇
    • 转载:1953篇
    • 译文:3篇
    • 评论:69条
    文章分类
    最新评论
    博客推荐
    http://www.vpser.net/