Netty优雅退出机制shutdownGracefully源码分析
程序员文章站
2022-04-22 21:56:08
...
使用netty开发的小伙伴对netty下面这两句代码应该非常熟悉了,netty的优雅退出机制
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
首先看其中的shutdownGracefully()方法,其中的参数quietPeriod为静默时间,timeout为截止时间,
第三个参数是TimeUnit unit为时间单位,其中该类还定义了一个变量gracefulShutdownStartTime,即优雅关闭开始时间,代码如下:
@Override
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
for (EventExecutor l: children) {
l.shutdownGracefully(quietPeriod, timeout, unit);
}
return terminationFuture();
}
@Override
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
if (quietPeriod < 0) {
throw new IllegalArgumentException("quietPeriod: " + quietPeriod + " (expected >= 0)");
}
if (timeout < quietPeriod) {
throw new IllegalArgumentException(
"timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))");
}
if (unit == null) {
throw new NullPointerException("unit");
}
if (isShuttingDown()) {
return terminationFuture();
}
boolean inEventLoop = inEventLoop();
boolean wakeup;
int oldState;
for (;;) {
if (isShuttingDown()) {
return terminationFuture();
}
int newState;
wakeup = true;
oldState = state;
if (inEventLoop) {
newState = ST_SHUTTING_DOWN;
} else {
switch (oldState) {
case ST_NOT_STARTED:
case ST_STARTED:
newState = ST_SHUTTING_DOWN;
break;
default:
newState = oldState;
wakeup = false;
}
}
if (STATE_UPDATER.compareAndSet(this, oldState, newState)) {
break;
}
}
gracefulShutdownQuietPeriod = unit.toNanos(quietPeriod);
gracefulShutdownTimeout = unit.toNanos(timeout);
if (ensureThreadStarted(oldState)) {
return terminationFuture;
}
if (wakeup) {
wakeup(inEventLoop);
}
return terminationFuture();
}
这段代码考虑了多线程同时调用关闭的情况,我们抓住其中的关键点,该方法只是将线程状态修改为ST_SHUTTING_DOWN
并不执行具体的关闭操作(类似shutdown方法将线程状态修改为ST_SHUTDOWN)。for()循环是为了保证修改state的线程(原生
线程或者外部线程)有且只有一个,并且通过CAS操作来确保线程安全。所以这段代码的关键在于修改STATE_UPDATER状态,
如果已经执行了shuttingDown操作直接返回,否则会继续向下执行
下面是wakeup(inEventLoop);
@Override
protected void wakeup(boolean inEventLoop) {
if (!inEventLoop && wakenUp.compareAndSet(false, true)) {
//调用wakeup方法唤醒selector阻塞
selector.wakeup();
}
}
唤醒selector阻塞。