上一篇文章提到了NioEventLoopGroup,那么这篇文章就要提到NioEventLoop了,可以简单的理解为一个NioEventLoopGroup中有很多NioEventLoop真正的执行工作。
首先我们还是来看一下NioEventLoop的继承体系:
其实相对还是比较直线型的集成体系。。
首先在AbstractEventExecutor中定义了一些基本的executor的方法,例如submit任务,调度任务等。
接着,在SingleThreadEventExecutor中则进行了一些详细的定义,我们来看看它的构造函数,基本上就明白了:
//构造函数
protected SingleThreadEventExecutor(
EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {
if (threadFactory == null) {
throw new NullPointerException("threadFactory");
}
this.parent = parent;
this.addTaskWakesUp = addTaskWakesUp;
thread = threadFactory.newThread(new Runnable() { //创建线程
@Override //线程的执行函数
public void run() {
CURRENT_EVENT_LOOP.set(SingleThreadEventExecutor.this);
boolean success = false;
updateLastExecutionTime();
try {
SingleThreadEventExecutor.this.run(); //开始当前executor的执行函数
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
if (state < ST_SHUTTING_DOWN) {
state = ST_SHUTTING_DOWN;
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
logger.error(
"Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must be called " +
"before run() implementation terminates.");
}
try {
// Run all remaining tasks and shutdown hooks.
for (;;) {
if (confirmShutdown()) {
break;
}
}
} finally {
try {
cleanup();
} finally {
synchronized (stateLock) {
state = ST_TERMINATED;
}
threadLock.release();
if (!taskQueue.isEmpty()) {
logger.warn(
"An event executor terminated with " +
"non-empty task queue (" + taskQueue.size() + ')');
}
}
}
}
}
});
taskQueue = newTaskQueue(); //构造任务队列
}
在构造函数中定义了执行线程,并且还构造了任务队列,用于保存当前executor需要执行的所有任务。
接下来就是SingleThreadEventLoop,它继承自SingleThreadEventExecutor,这其实和group里面的差不多,我们最终用的是eventloop,但是eventloop本身也是一个eventexecutor。
在SingleThreadEventLoop中,定一些一些eventloop的基本方法,例如register方法。
最后就是NioEventLoop了,在它里面实现了各种事件循环的方法,其实最重要的还是run方法,这也是在singlethreadexecutor中线程要执行的方法,我们来看看它的定义吧:
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();
processSelectedKeys(); //处理所有选出来的key
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.
}
}
}
}
就这样,NioEventLoop和NioEventLoopGroup两条主线就差不多了,可以有以下总结,
EventLoop里面会包含EventExecutor,也就是说事件循环同时也是一个事件的执行器,group可以把它看做是一个容器。。。。
接下来可以分析Netty里面channel的定义了。。。。。