介绍Netty是一个异步NIO框架,多线程肯定是它的基础,但是对于netty的实际使用者来说,一般不需要接触多线程,我们只需要按照netty框架指定的进程,自定义handler来处理相应的消息。那么有朋友会问,作为一个NIO框架,netty的多线程体现在哪里呢?它的基本原理是什么?今天就带大家看一下netty中的任务执行器EventExecutor和EventExecutorGroup。EventExecutorGroup因为EventExecutor继承自EventExecutorGroup,这里先详细说明一下EventExecutorGroup。先看EventExecutorGroup的定义:publicinterfaceEventExecutorGroupextendsScheduledExecutorService,IterableEventExecutorGroup继承自JDK的ScheduledExecutorService,可以像普通任务执行器一样执行定时任务或者提交任务执行。同时EventExecutorGroup也继承了Iterable接口,也就是说EventExecutorGroup是可遍历的,它的遍历对象是EventExecutor。EventExecutorGroup有两个和Iterable相关的方法,分别是next和iterator:EventExecutornext();@OverrideIterator迭代器();调用EventExecutorGroup中的next方法会返回一个EventExecutor对象,那么EventExecutorGroup和EventExecutor毛布有什么关系呢?我们再看一下EventExecutor的定义:publicinterfaceEventExecutorextendsEventExecutorGroup可以看到EventExecutor其实是EventExecutorGroup的子类。但是实际上在父类EventExecutorGroup中有对子类EventExecutor的引用。这种在父类的组中引用并返回子类的设计模式在netty中很常见。这种设计是好是坏,大家可以自己去体会。EventExecutorGroup是EventExecutor的一个Group对象,用于管理组内的EventExecutor。因此,在EventExecutorGroup中设计了一些EventExecutor的统一管理接口。例如,booleanisShuttingDown()方法用于判断该组中的所有EventExecutor是否正在关闭或已经关闭。另外EventExecutorGroupt提供了关闭组中所有EventExector的方法:Future>shutdownGracefully()和终止方法:Future>terminationFuture()。这两个方法都返回Future,所以我们可以认为这两个方法是异步的。EventExecutorGroup中的其他方法是对JDK中ScheduledExecutorService方法的一些重写,如submit、schedule、scheduleAtFixedRate、scheduleWithFixedDelay等。EventExecutor接下来我们再研究一下EventExecutor。在上一节中,我们简单提到了EventExecutor继承自EventExecutorGroup。与EventExecutorGroup相比,EventExecutor有哪些新方法?我们知道EventExecutorGroup继承了Iterable,定义了一个next方法返回Group中的一个EventExecutor对象。因为Group中有很多EventExecutor,返回哪个EventExecutor还是由具体的实现类来实现。在EventExecutor中,它覆盖了这个方法:@OverrideEventExecutornext();这里的next方法返回EventExecutor本身。另外,由于EventExecutor是由EventExecutorGroup管理的,所以在EventExecutor中还有一个parent方法返回管理EventExecutor的EventExecutorGroup:EventExecutorGroupparent();EventExecutor新增两个inEventLoop方法,用于判断给定线程是否在事件循环中执行。布尔inEventLoop();booleaninEventLoop(Threadthread);EventExecutor也提供了两个返回Promise和ProgressivePromise的方法。PromisenewPromise();ProgressivePromisenewProgressivePromise();熟悉ECMAScript的朋友可能知道,Promise是ES6为解决回调地狱问题而引入的新语法特性。这里netty引入的Promise继承自Future,增加了成功和失败两种状态。ProgressivePromise更进了一步。在Promise的基础上,提供了一个progress来表示进度。此外,EventExecutor还提供了将Succeeded结果和Failed异常封装到Futures中的方法。未来newSucceededFuture(V结果);未来newFailedFuture(Throwable原因);netty中EventExecutorGroup的基本实现EventExecutorGroup和EventExecutor在netty中有很多非常重要的实现,其中最常见的就是EventLoop和EventLoopGroup。鉴于EventLoop和EventLoopGroup的重要性,我们将在后面的章节重点讲解。我们先看看netty中的其他实现。EventExecutorGroup在netty中默认的实现称为DefaultEventExecutorGroup,其继承关系如下:/>可以看到DefaultEventExecutorGroup继承自MultithreadEventExecutorGroup,MultithreadEventExecutorGroup继承自AbstractEventExecutorGroup。首先看一下AbstractEventExecutorGroup的逻辑。AbstractEventExecutorGroup基本上是EventExecutorGroup中接口的一些实现。我们知道在EventExecutorGroup中定义了一个next()方法,可以返回Group中的一个EventExecutor。在AbstractEventExecutorGroup中,EventExecutorGroup中几乎所有的方法都是通过调用next()方法来实现的。以提交方法为例:publicFuture>submit(Runnabletask){returnnext().submit(task);可以看到submit方法是先调用next获取到的EventExecutor,然后再调用EventExecutor中的submit方法。AbstractEventExecutorGroup中的其他方法都是这样实现的。然而,next()方法并没有在AbstractEventExecutorGroup中实现。如何从Group中获取EventExecutor取决于底层的具体实现。MultithreadEventExecutorGroup继承自AbstractEventExecutorGroup,提供对多线程任务的支持。MultithreadEventExecutorGroup有两种类型的构造函数。在构造函数中可以指定多线程的个数,以及任务执行器Executor。如果未提供Executor,则可以提供ThreadFactory。MultithreadEventExecutorGroup会调用newThreadPerTaskExecutor(threadFactory)为每个线程创建一个新的线程。构造一个执行器:protectedMultithreadEventExecutorGroup(intnThreads,ThreadFactorythreadFactory,Object...args){this(nThreads,threadFactory==null?null:newThreadPerTaskExecutor(threadFactory),args);}protectedMultithreadEventExecutorGroup(intnThreads,executorObject...args){this(nThreads,executor,DefaultEventExecutorChooserFactory.INSTANCE,args);MultithreadEventExecutorGroup如何支持多线程?首先,MultithreadEventExecutorGroup提供了两个children,分别是children和readonlyChildren:privatefinalEventExecutor[]children;privatefinalSetreadonlyChildren;children中的线程数和MultithreadEventExecutorGroup是一一对应的。它有多大。children=newEventExecutor[nThreads];然后通过调用newChild方法,将传入的executor构造成一个EventExecutorreturn:children[i]=newChild(executor,args);查看newChild方法的定义:protectedabstractEventExecutornewChild(Executorexecutor,Object...args)throwsException;该方法在MultithreadEventExecutorGroup中没有实现,需要在更具体的类中实现。readonlyChildren是child的只读版本,用于遍历方法中返回:readonlyChildren=Collections.unmodifiableSet(childrenSet);publicIteratoriterator(){returnreadonlyChildren.iterator();我们现在有了所有的EventExecutor,那么在MultithreadEventExecutorGroup中,next方法如何选择返回哪个EventExecutor呢?先看下方法的定义:privatefinalEventExecutorChooserFactory.EventExecutorChooserchooser;选择器=chooserFactory.newChooser(children);publicEventExecutornext(){returnchooser.next();}next方法调用chooser的next方法,看下面看chooser的next方法的具体实现:publicEventExecutornext(){returnexecutors[(int)Math.abs(idx.getAndIncrement()%executors.length)];}可以看到,其实就是一个非常简单的方法,根据index获取对象的操作。最后看下DefaultEventExecutorGroup中newChild方法的实现:1]);newChild返回的EventExecutor使用DefaultEventExecutor。这个类是netty中EventExecutor的默认实现,我们会在接下来的总结中详细讲解。netty中EventExecutor的基本实现netty中EventExecutor的默认实现是DefaultEventExecutor,先看它的继承结构:67%;”/>DefaultEventExecutor继承自SingleThreadEventExecutor,SingleThreadEventExecutor继承自AbstractScheduledEventExecutor,AbstractScheduledEventExecutor继承自AbstractEventExecutor。先看AbstractEventExecutor的定义:publicabstractclassAbstractEventExecutorextendsAbstractExecutorServiceimplementsEventExecutorAbstractEventExecutor继承AbstractExecutorService,实现了EventExecutor接口。AbstractExecutorService是JDK中的一个类,提供了ExecutorService的一些实现,如submit、invokeAny、invokeAll。AbstractEventExecutor作为ExecutorGroup的成员,提供了一个EventExecutorGroup类型的parent属性:privatefinalEventExecutorGroupparent;publicEventExecutorGroupparent(){返回父级;}对于next方法,AbstractEventExecutor返回自身:publicEventExecutornext(){returnthis;}AbstractScheduledEventExecutor继承自AbstractEventExecutor。它内部使用一个PriorityQueue来存储包含定时任务的ScheduledFutureTask,从而实现定时任务的功能:PriorityQueue>scheduledTaskQueue;接下来是SingleThreadEventExecutor,从名字就可以看出,SingleThreadEventExecutor使用单线程来执行提交的任务。SingleThreadEventExecutor为待执行的任务提供了默认的任务大小:DEFAULT_MAX_PENDING_EXECUTOR_TASKS,同时也定义了任务执行的几种状态:privatestaticfinalintST_NOT_STARTED=1;privatestaticfinalintST_STARTED=2;私人静态最终intST_SHUTTING_DOWN=3;私人静态最终intST_SHUTDOWN=4;privatestaticfinalintST_TERMINATED=5;前面提到,EventExecutor中有一个独特的inEventLoop方法来判断给定的线程是否在eventLoop中,在SingleThreadEventE中在xecutor中,我们看一下具体实现:publicbooleaninEventLoop(Threadthread){returnthread==this.thread;}具体来说就是判断给定的线程和SingleThreadEventExecutor中定义的线程属性是否是同一个线程,SingleThreadEventExecutor中的线程是这样定义的:这个线程在doStartThread方法中初始化:executor.execute(newRunnable(){@Overridepublicvoidrun(){thread=Thread.currentThread();所以这个线程就是任务执行线程,也就是executor中用来执行任务的线程我们来看看非常关键的execute方法:privatevoidexecute(Runnabletask,booleanimmediate){booleaninEventLoop=inEventLoop();addTask(task);if(!inEventLoop){startThread();该方法首先将任务添加到任务队列中,然后调用startThread启动线程线程来执行任务。最后看一下DefaultEventExecutor,这个netty中的默认实现:publicfinalclassDefaultEventExecutorextendsSingleThreadEventExecutorDefaultEventExecutor继承自SingleThreadEventExecutor,在这个类中,定义了run方法的实现方式:protectedvoidrun(){for(;;){可运行任务=takeTask();if(task!=null){task.run();updateLastExecutionTime();}if(confirmShutdown()){中断;在SingleThreadEventExecutor中,我们将任务添加到任务队列中,在run方法中,会从任务队列中取出对应的任务,然后调用任务的run方法执行。总结DefaultEventExecutorGroup继承了MultithreadEventExecutorGroup,MultithreadEventExecutorGroup实际上调用了SingleThreadEventExecutor来执行特定的任务。本文已收录于http://www.flydean.com/05-1-netty-event…entexecutorgroup/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!