Netty入门(三):EventLoop

1.Java基础(一):I/O多路复用模型及Linux中的应用

Netty入门(三):EventLoop

上文提到,早期基于线程的网络模型,处理高并发的能力非常差,随着请求数量的增多,必须不断新建线程,随之带来的问题就是服务器资源被占满、上下文切换成本过高以及IO阻塞导致的CPU浪费。

Netty则使用了经典Reactor模型,并重新进行了封装,包括EventLoop、EventGroup等。

EventLoopGroup

EventLoopGroup是一个接口,继承自线程池EventExecutorGroup,并允许注册channel到自身所持有的EventLoop,同时支持按一定规则获取下一个EventLoop。

EventLoopGroup的具体实现有很多,下面以DefaultEventLoopGroup为例,简述一下我的理解

Netty入门(三):EventLoop

1.ScheduledExecutorService

JDK接口,一个延迟或定时任务的执行器,其实现类ScheduledThreadPoolExecutor主要是利用了延时队列及设置下次执行时间来实现的,这里不再赘述(可以单独开个专题0.0)

2.EventExecutorGroup

接口,Netty自定义的一个线程池,负责复用EventExecutor和执行任务

Netty入门(三):EventLoop

3.EventLoopGroup

核心接口,EventLoopGroup继承自EventExecutorGroup,代表他是一个线程池。同时他具备将channel注册到EventExecutorGroup的功能,代表他是一个能够真正处理Channel的特殊线程池

Netty入门(三):EventLoop

4.MultithreadEventExecutorGroup(AbstractEventExecutorGroup)

抽象类,实现自EventExecutorGroup接口,提供了一个简易线程池的实现,其只有一个抽象方法newChild(创建EventExecutor)供子类实现

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args)

4.1 nThreads

private final EventExecutor[] children;

该线程池通过数组存储线程,入参nThreads指定数组大小,并循环调用newChild创建线程。当创建过程中有异常时,会自动调用已创建完成线程的shutdownGracefully方法,进行优雅关闭

for (int i = 0; i < nThreads; i ++) { boolean success = false; try { children[i] = newChild(executor, args); success = true; } catch (Exception e) { // TODO: Think about if this is a good exception type throw new IllegalStateException("failed to create a child event loop", e); } finally { if (!success) { for (int j = 0; j < i; j ++) { children[j].shutdownGracefully(); } for (int j = 0; j < i; j ++) { EventExecutor e = children[j]; try { while (!e.isTerminated()) { e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS); } } catch (InterruptedException interrupted) { // Let the caller handle the interruption. Thread.currentThread().interrupt(); break; } } } } }

4.2 EventExecutorChooserFactory

EventExecutorChooserFactory是一个工厂接口,负责创建EventExecutorChooser

其默认实现DefaultEventExecutorChooserFactory会判断当前线程数是否2的n次幂,如果是则返回PowerOfTwoEventExecutorChooser,否则返回GenericEventExecutorChooser

4.3 EventExecutorChooser

private final EventExecutorChooserFactory.EventExecutorChooser chooser;

EventExecutorChooser负责根据一定规则从线程池children数组中取得下一个线程

PowerOfTwoEventExecutorChooser:通过&运算,将超出executors.length的位置为0

public EventExecutor next() { return executors[idx.getAndIncrement() & executors.length - 1]; }

GenericEventExecutorChooser:通过求余运算,获取有效index

public EventExecutor next() { return executors[Math.abs(idx.getAndIncrement() % executors.length)]; }

可以看出当线程数是2的n次幂时,Netty通过与运算优化了效率

5.MultithreadEventLoopGroup

抽象类,继承自MultithreadEventExecutorGroup并实现了EventLoopGroup接口,代表此抽象类是一个可以注册并处理channel的线程池

Netty入门(三):EventLoop

值得关注的是next方法,他把返回值的类型,进一步限定为EventLoop

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

MultithreadEventLoopGroup的一个默认实现

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwzwx.html