其实,我觉得netty的源码还是有点恶心的,特别是注解,很多相应的方法和属性的都没有写上注释,只有在抽象接口中有方法的说明,而子类的相关细节却被完完全全的忽略,笔者这样增加了开发人员的netty的研读,也加大理解netty架构的难度
先讲一下EventExecutorGroup的功能吧,EventExecutorGroup看到event、executor、group就知道他是一个与线程、事件以及群组的功能了,也就是他根据通道相应的事件对通道进行处理,而这个处理也有可能是多个线程的多线程处理
我们先来看一下EventExecutorGroup的类的结构吧
首先,我们来看第(1)部分的基本方法
EventExecurotGroup
MultithreadEventLoopGroup
可见由于继承了ScheduledExecutorService和Iterator,EventExecutorGroup具备了一些线程和iterator最基本的方法,而MultithreadEventLoopGroup底层有多个EventExecutor数组进行处理而已
接着我们来看一下第(3)部分基本方法
EventExecutor是一个特殊的EventExecutorGroup带来一些便捷的方法(inEventLoop()、inEventLoop(Thread))去检查一个线程是否在一个事件循环中执行。 而且它也扩展了EventExecutorGroup访问方法允许一个通用的方法。
接下来我们再看第(2)部分
可见EventLoopGroup其实就是一个真正为Channel处理的相关的相关子类,具备有将channel注册到EventExecutorGroup的selector的功能
所以第(2)部分才是基于nio的Channel编程的netty实现的功能所在了,而其他两个部分更多的像是提供一种中间辅助类的功能,以及相应方法实现的封装了
以下过程可能会有点复杂,但记得对照类的结构图来看,还是很容易理解的
接下来,我们从netty第一篇文章的相应片段开始
我们再来看一以下NioEventLoopGroup(他也是一个EventLoopGroup)中的处理
再看基类MultithreadEventLoopGroup的处理
可见它是根据当前cpu处理器个数的两倍来充当线程数(此时nThreads为 0)
我们再看基类 MultithreadEventExecutorGroup怎么处理
再看newChild的本例的实现类
由此可见child数组的每个元素其实是一个NioEventLoop对象
再看super(parent,threadfactory,selectorProvider)在基类的代码
所以每个child数组元素的线程就在此处创建:
thread = threadFactory.newThread(new Runnable()
同时也创建了线程的任务队列,是一个LinkedBlockingQueue结构。
再看SingleThreadEventExecutor.this.run()在本例中是NioEventLoop
@Override
protected void run() {
for (;;) {
oldWakenUp = wakenUp.getAndSet(false);
try {
if (hasTasks()) { //如果有任务,马上进行选择(非阻塞)
selectNow();
} else {
select();
// 'wakenUp.compareAndSet(false, true)' is always evaluated
// before calling 'selector.wakeup()' to reduce the wake-up
// overhead. (Selector.wakeup() is an expensive operation.)
//
// However, there is a race condition in this approach.
// The race condition is triggered when 'wakenUp' is set to
// true too early.
//
// 'wakenUp' is set to true too early if:
// 1) Selector is waken up between 'wakenUp.set(false)' and
// 'selector.select(...)'. (BAD)
// 2) Selector is waken up between 'selector.select(...)' and
// 'if (wakenUp.get()) { ... }'. (OK)
//
// In the first case, 'wakenUp' is set to true and the
// following 'selector.select(...)' will wake up immediately.
// Until 'wakenUp' is set to false again in the next round,
// 'wakenUp.compareAndSet(false, true)' will fail, and therefore
// any attempt to wake up the Selector will fail, too, causing
// the following 'selector.select(...)' call to block
// unnecessarily.
//
// To fix this problem, we wake up the selector again if wakenUp
// is true immediately after selector.select(...).
// It is inefficient in that it wakes up the selector for both
// the first case (BAD - wake-up required) and the second case
// (OK - no wake-up required).
if (wakenUp.get()) {
selector.wakeup();
}
}
cancelledKeys = 0;
final long ioStartTime = System.nanoTime();
needsToSelectAgain = false;
if (selectedKeys != null) {
processSelectedKeysOptimized(selectedKeys.flip());
} else {
processSelectedKeysPlain(selector.selectedKeys());
}
final long ioTime = System.nanoTime() - ioStartTime;
final int ioRatio = this.ioRatio;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
break;
}
}
} catch (Throwable t) {
logger.warn("Unexpected exception in the selector loop.", t);
// Prevent possible consecutive immediate failures that lead to
// excessive CPU consumption.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Ignore.
}
}
}
}
至此,NioEventLoopGroup创建完毕了
总结:
EventLoopGroup bossGroup = new NioEventLoopGroup()发生了以下事情:
1、 为NioEventLoopGroup创建数量为:处理器个数 x 2的,类型为NioEventLoop的实例。每个NioEventLoop实例 都持有一个线程,以及一个类型为LinkedBlockingQueue的任务队列
2、线程的执行逻辑由NioEventLoop实现
3、每个NioEventLoop实例都持有一个selector,并对selector进行优化。