Netty
服务端启动完成,这时候客户端连接就可以接入进来了,下面我们就来分析下客户端连接接入的流程。
之前分析过NioEventLoop
线程启动方法是startThread()
,由于这个方法里面的逻辑比较复杂,并没有展开,这一节就是从这个方法开始分析。
startThread
private void startThread() {
if (state == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
try {
doStartThread();
} catch (Throwable cause) {
STATE_UPDATER.set(this, ST_NOT_STARTED);
PlatformDependent.throwException(cause);
}
}
}
}
这个方法主要主要完成2件事:
-
利用
cas
将NioEventLoop
的状态由ST_NOT_STARTED
修改成ST_STARTED
,即表示NioEventLoop
线程启动; -
执行
doStartThread()
方法;
doStartThread()
方法看着比较复杂,核心逻辑如下,向线程池执行器executor
提交一个任务,而这个线程池执行器类型是ThreadPerTaskExecutor
,即每次执行任务都会创建一个新线程,而且这个任务是无限循环的:事件轮询selector.select()
、事件处理processSelectedKeys()
和任务队列处理runAllTasks()
,这样NioEventLoop
就和具体的Thread
线程进行了关联:
private void doStartThread() {
assert thread == null;
//executor线程执行器,类型是:ThreadPerTaskExecutor,即每次执行任务都会创建一个新线程
executor.execute(new Runnable() {
@Override
public void run() {
//将executor线程执行器创建的线程:FastThreadLocalThread保存到EventLoop的全局变量中,相当于thread和EventLoop的绑定
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
//然后调用EventLoop中的run方法进行启动
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
}
}
});
}
该方法大致完成2件事:
-
thread = Thread.currentThread();
:将executor
线程池分配的线程保存起来,这样就完成了NioEventLoop
和Thread
线程的关联; -
SingleThreadEventExecutor.this.run()
:具体实现在NioEventLoop.run()
方法,所以,startThread()
核心就是分配一个线程运行NioEventLoop.run()
方法。
protected void run() {
for (;;) {
try {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:// 默认实现下,不存在这个情况
continue;
case SelectStrategy.BUSY_WAIT:
case SelectStrategy.SELECT:
//selector.select轮询io事件
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
default:
}
} catch (IOException e) {
rebuildSelector0();
handleLoopException(e);
continue;
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100)&nb