乐趣区

关于java:netty系列之EventLoopEventLoopGroup和netty的默认实现

简介

在 netty 中不论是服务器端的 ServerBootstrap 还是客户端的 Bootstrap,在创立的时候都须要在 group 办法中传入一个 EventLoopGroup 参数,用来解决所有的 ServerChannel 和 Channel 中所有的 IO 操作和 event。

可能有的小伙伴还略微看了一下 netty 的源码,可能会发现还有一个和 EventLoopGroup 十分相似的类叫做 EventLoop。那么 EventLoopGroup 和 EventLoop 有什么关系呢?他们的底层和 channel 的交互关系是怎么样的呢?一起来看看吧。

EventLoopGroup 和 EventLoop

EventLoopGroup 继承自 EventExecutorGroup:

public interface EventLoopGroup extends EventExecutorGroup 

在后面的文章中咱们讲过,EventExecutorGroup 中有一个 next 办法能够返回对应的 EventExecutor,这个办法在 EventLoopGroup 中进行了重写:

    EventLoop next();

next 办法返回的不再是一个 EventExecutor,而是一个 EventLoop。

事实上,EventLoop 和 EventLoopGroup 的关系与 EventExecutor 和 EventExecutorGroup 的关系有些相似,EventLoop 也是继承自 EventLoopGroup,EventLoopGroup 是 EventLoop 的汇合。

public interface EventLoop extends OrderedEventExecutor, EventLoopGroup 

在 EventLoopGroup 中,除了重写的 next 办法之外,还增加了 channel 的注册办法 register, 用于将 channel 和注册到 EventLoop 中,从而实现 channel 和 EventLoop 的绑定。

ChannelFuture register(Channel channel);

在 EventLoop 中,自多增加了一个 parent 办法,用来示意 EventLoop 和 EventLoopGroup 的关联关系:

EventLoopGroup parent();

EventLoopGroup 在 netty 中的默认实现

EventLoopGroup 在 netty 中的默认实现叫做 DefaultEventLoopGroup,先来看一下它的继承关系:

<img src=”https://img-blog.csdnimg.cn/119283e9b8d04854940abc0fc159c604.png” style=”zoom:67%;” />

如果看了之前我解说的对于 EventExecutorGroup 的敌人能够看进去,DefaultEventLoopGroup 和 DefaultEventExecutorGroup 的继承关系是很相似的,DefaultEventLoopGroup 继承自 MultithreadEventLoopGroup, 而 MultithreadEventLoopGroup 又继承自 MultithreadEventExecutorGroup 并且实现了 EventLoopGroup 接口:

public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup 

MultithreadEventLoopGroup 是用多线程来解决 Event Loop。

在 MultithreadEventLoopGroup 中定义了一个 DEFAULT_EVENT_LOOP_THREADS 来存储默认的解决 Event Loop 线程的个数:

DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

对于 EventLoopGroup 中新加的几个 register 办法,MultithreadEventLoopGroup 都是调用对应的 next 办法来实现的:

public ChannelFuture register(Channel channel) {return next().register(channel);
    }

这里的 next() 办法的实现实际上调用的是父类的 next 办法,也就是 MultithreadEventExecutorGroup 中的 next 办法,来抉择 Group 治理的一个 EventLoop:

public EventLoop next() {return (EventLoop) super.next();}

对于 DefaultEventLoopGroup 来说,它继承自 MultithreadEventLoopGroup,实现了一个 newChild 办法,用来将传入的 executor 封装成为 EventLoop:

    protected EventLoop newChild(Executor executor, Object... args) throws Exception {return new DefaultEventLoop(this, executor);
    }

EventLoop 在 netty 中的默认实现

EventLoop 在 netty 中的默认实现叫做 DefaultEventLoop,先来看下它的继承关系:

<img src=”https://img-blog.csdnimg.cn/9c642b58f6c248f9bddfbb71799549f9.png” style=”zoom:67%;” />

DefaultEventLoop 继承自 SingleThreadEventLoop, 而 SingleThreadEventLoop 又继承自 SingleThreadEventExecutor 并且实现了 EventLoop 接口。

先来看下 SingleThreadEventLoop 的实现:

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop 

SingleThreadEventLoop 应用繁多线程来执行提交的工作。它和 SingleThreadEventExecutor 相比有什么变动呢?

首先 提供了一个 tailTasks 用来存储 pending 的 tasks:

private final Queue<Runnable> tailTasks;

这个 tailTasks 会被用在工作个数的判断和操作上:

    final boolean removeAfterEventLoopIterationTask(Runnable task) {return tailTasks.remove(ObjectUtil.checkNotNull(task, "task"));
    }

    protected boolean hasTasks() {return super.hasTasks() || !tailTasks.isEmpty();}

    public int pendingTasks() {return super.pendingTasks() + tailTasks.size();}

SingleThreadEventLoop 中对 register 办法的实现最终调用的是注册的 channel 中 unsafe 的 register 办法:

channel.unsafe().register(this, promise);

再来看一下 DefaultEventLoop,DefaultEventLoop 继承自 SingleThreadEventLoop:

public class DefaultEventLoop extends SingleThreadEventLoop 

除了构造函数之外,DefaultEventLoop 实现了一个 run 办法, 用来具体任务的执行逻辑:

    protected void run() {for (;;) {Runnable task = takeTask();
            if (task != null) {task.run();
                updateLastExecutionTime();}

            if (confirmShutdown()) {break;}
        }
    }

如果比照能够发现,DefaultEventLoop 和 DefaultEventExecutor 中 run 办法的实现是一样的。

总结

本文介绍了 netty 中 EventLoop 和 EventLoopGroup 的默认实现:DefaultEventLoop 和 DefaultEventLoopGroup,然而不晓得小伙伴们有没有发现,即便在最简略的 netty 利用中也很少看到这两个默认的 EventLoop。最罕用的反而是 NioEventLoopGroup 和 NioEventLoop,这是因为 DefaultEventLoop 和 DefaultEventLoopGroup 只是应用了多线程技术,一个线程代表一个 EventLoop,在 EventLoop 过多的状况下可能会造成线程和性能的节约,所以在 NioEventLoopGroup 和 NioEventLoop 应用了 NIO 技术,通过应用 channel、selector 等 NIO 技术晋升了 EventLoop 的效率。对于 NioEventLoopGroup 和 NioEventLoop 的具体介绍,咱们会在后一章中具体解说,敬请期待。

本文已收录于 http://www.flydean.com/05-1-netty-eventloop-eventloopgroup/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

退出移动版