两篇文章看懂EventLoopGroup,EventLoop的设计和运行机制(二)

本文深入剖析了Netty中EventLoopGroup和EventLoop的设计和运行机制,从EventExecutorGroup和EventExecutor接口出发,探讨了它们在多线程事件执行器组、单线程事件执行器、线程池等方面的角色和功能。重点讲解了EventLoopGroup的实现,如MultithreadEventLoopGroup和NioEventLoopGroup,以及它们如何管理EventLoop并处理IO和非IO事件。此外,文章还介绍了EventLoop在处理任务调度、中断监听等方面的实现细节,揭示了其内部的事件循环和多路复用器的工作原理。
摘要由CSDN通过智能技术生成

前言

上一篇更多的是说结论,那结论是怎么来的呢?也是一步一步学习出来的,我在学习过程中,使用了Xmind,用来做思维导图还是比较好的,层次结构以及每个方法都可以很好的记录。本文重点分享一下下面这个类图以及每个类中的实现细节:
在这里插入图片描述

EventExecutorGroup和EventExecutor

这两个接口是上述类图中的基础,也是EventLoop的基础,特别是EventExecutorGroup,是netty自定义的第一个接口,先学习好它们,也就能学习好EventLoop了。
还是按照我的思路,先删减,后增补。

EventExecutorGroup

先看一下拆分的类图:
在这里插入图片描述
它本身继承了4个重要接口,以及它们各自的功能:

  • Iterable:迭代器接口,返回一个迭代器。说明已经具备了Group的管理或者容器功能。
  • Executor:具备了提交任务的能力。
  • ExecutorService:具备了线程池的能力。
  • ScheduledExecutorService:具备了执行调度任务的能力。

这4种能力不多说,都是JDK本身提供的,我们杰西莱看一下,它本身定义了哪些方法呢?如下图:
在这里插入图片描述
虽然有很多方法,但大多数都是上面接口的,重新写了一遍而已,我们对它新加的一些方法做一些分析。

  • 它优化了JDK提供的关于中断的方法:标记过时(shutdown,shutdownNow),并且新加了几个方法
    • boolean isShuttingDown();
    • Future<?> shutdownGracefully();
    • Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit);
  • 增加了一个中断状态监听的方法
    • Future<?> terminationFuture()。注意这个Future是netty的.
    • 可以在这个future上面增加一些监听器(addListener),然后当中断的时候就会触发。
  • 增加了next方法。返回的是由它管理的EventExecutor。这个组的味道已经出现了。这个也是后面实现轮询内部成员的一个关键方法。
    这个接口的功能就是:线程池,管理一组EventExecutor,调度任务,中断监听。

我们单从Group的功能来看的话,这个接口下面就再也没有其它接口了,都是一些抽象类了,下面是一个比较简单的类图:
在这里插入图片描述

AbstractEventExecutorGroup

这个类没有任何的实现,仅仅只是把所有的提交任务的方法做了一下默认实现:就是调用一些next()方法轮询出来一个Executor然后去执行,比如:

  @Override
    public void execute(Runnable command) {
   
        next().execute(command);
    }

其它的所有方法都没有实现,也确实挺抽象的。
不过这个抽象类的作用还是非常大的,之前在分析组和成员关系的时候,组也具备了一些成员关系的功能,但是它的执行就是通过成员去完成的,而且这些功能本身也确实不需要组去关心的。而netty就是把这些功能放在了这个类里面,也放的特别合适,它没有实现任何有关于的组的管理功能,实际上就是交给子类去完成了,而子类在实现管理功能的时候,也就不需要关心这些功能了(提交任务),父类都已经实现了。

MultithreadEventExecutorGroup

听名字就可以听出来一些味道了:多线程事件执行器组。
3个关键词:多线程,事件执行器,组。
这个里面才是真正实现了组的管理功能,看一下它内部所有的属性和方法:

在这里插入图片描述
先看一下内部属性吧:

  • EventExecutor[] children:固定大小的EventExecutor数组,构造器里面会根据大小全部初始化成员。
  • EventExecutorChooser chooser:成员轮询器。虽然有两种实现,但其实都是按照(0,1,2,3,…,n-1)的顺序来的。只不过当大小是2的幂的时候,采用了一下位的和(&)运算,会稍微快一些。这个就是next方法的实现。
  • terminationFuture:中断的一个Future,可以用来监听中断事件。
  • readonlyChildren:用一个不可写的集合来做迭代器用。
  • terminatedChildren:原子int,用来标记当前有多少个成员已经被中断了,当所有的都被中断的时候,就会触发中断事件。

这个类比较核心的就是它的构造器了,至于其它的关于中断的方法,基本上也都是循环中断所有的成员,不是特别复杂。当然还有一个创建成员的抽象方法,不过也是和构造器相呼应的。

关于它的构造器和一个抽象方法,我觉得也是比较有趣的点。

  • 它的所有的构造器都是protected的,说明不是对外开放的,由子类去调用的。

  • 最有趣的在于构造器的最后一个参数居然是:Object… args。在构造器里面,这种写法确实还是比较少见的。

  • 这个类仅有一个抽象方法:

    protected abstract EventExecutor newChild(Executor executor, 	Object... args) throws Exception
    

    就是在初始化成员的时候需要调用的方法,而且它的最后一个参数也是 Object… args。其实构造器的对象数组的入参和这个入参是相呼应的,就是同一个。

  • 这个构造器当时在定义的时候,开发人员估计费了不少的心思啊,哈哈。

  • 那为什么要这样写呢?那肯定是为了复用,复用这些组的管理功能。它所管理的Executor到底需要哪些参数,以及如何来创建。它不关心,它也没法关心;所以留到了子类,同时它希望对于具体的子类而已,那个对象数组不能暴露给框架的使用人员,希望他们具体化,不能这么抽象的使用,所以构造器全部protected。

MultithreadEventExecutorGroup到这边就结束了,它更多的是完成了成员的初始化以及中断的相关内容。但是成员EventExecutor到底什么?且看下面的分析。

DefaultEventExecutorGroup

这个类非常简单,提供了3个构造器,实现了newChild方法,并且明确了成员就是DefaultEventExecutor。
当我学习到这边的时候,就基本非常明确了,它就是一个线程池,我第一个想到的就是和ThreadPoolExecutor进行比较,之前的文章以及比较过了。但是在比较之前,想了一下,我好像还并不知道任务是怎么执行的,也就是EventExecutor的具体实现了。

EventExecutor

这个接口才是真正的执行任务的接口:
在这里插入图片描述
它继承了EventExecutorGroup,说明它也拥有上面说的所有功能。
重点关注一下,它新定义的方法吧:
在这里插入图片描述
它基本上新定义了3类接口:

  • parent():返回父节点。也反映了它被EventExecutorGroup管理的特性。
  • inEventLoop():判断当前线程是不是当前EventExecutor所关联的事件循环的线程。非常重要的方法,好多地方都会用到。因为在后续的提交任务的时候,有可能是事件循环的线程(这个就是提交的任务在执行过程当中又提交了新的任务),有可能是其它线程。然后可能需要做一些线程安全方面的工作。
  • 创建Promise,或者Future的方法。这个我没有用过,但是也了解了一些,简单说一下,可能不太对。这两种对象都代表的是异步执行的结果,前者相对于后者具备了写的功能,后者只可读。但是他们都具备结束然后事件通知的能力,那么谁来通知呢?就是当前EventExector所关联的线程去通知。也就是通过它创建的,都会用它的关联线程去执行通知任务。但是具体的应用场景还不太清楚。

以后就是它比Group多出来的方法,一方面体现了它是成员角色,另一方面它也可以做额外的事情。从下面开始,也就没有接口定义了,都是具体的类了。

然后再看一下DefaultEventExecutor的整体类图:
在这里插入图片描述

AbstractEventExecutor

这个类一方面实现了EventExecutor,另一方也继承了JDK提供的AbstractExecutorService。后面这个类更多的是提供提交一些任务的默认实现,也没有做具体的业务实现。
AbstractEventExecutor它本身也没有做太多事情,只是把接口和抽象类整合在了一起。稍微梳理一下吧:
在这里插入图片描述

  • parent:定义了父对象。

  • selfCollection:返回一个属于自己的迭代器。

  • promise,future的方法都做了实现,如下:

    @Override
    public <V> Promise<V> newPromise() {
         
        return new DefaultPromise<V>(this);
    }
    
    @Override
    public <V> ProgressivePromise<V> newProgressivePromise() {
         
        return new DefaultProgressivePromise<V>(this);
    }
    
    @Override
    public <V> Future<V> newSucceededFuture(V result) {
         
        return new SucceededFuture<V>(this, result);
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值