上一篇主要介紹了一下
EventLoopGroup
,本篇詳細看下它的成員EventLoop
。
類結構
NioEventLoop
繼承自SingleThreadEventLoop
,而SingleThreadEventLoop
又繼承自SingleThreadEventExecutor
。
SingleThreadEventExecutor
內部持有一個Thread物件,是Netty
多執行緒的基礎。
可以認為, 一個NioEventLoop
與一個特定的執行緒進行了繫結,並且在其生命週期內,繫結的執行緒都不會再改變。
SingleThreadEventExecutor
從名字就可以看出來,SingleThreadEventExecutor
是一個單執行緒事件執行器。主要做的事情就是執行緒的管理和事件的執行。
執行緒管理
SingleThreadEventExecutor
中定義了五種執行緒狀態:
/**
* 未開始
*/
private static final int ST_NOT_STARTED = 1;
/**
* 已開始
*/
private static final int ST_STARTED = 2;
/**
* 關閉中
*/
private static final int ST_SHUTTING_DOWN = 3;
/**
* 已關閉
*/
private static final int ST_SHUTDOWN = 4;
/**
* 已終止
*/
private static final int ST_TERMINATED = 5;
複製程式碼
這幾種狀態對應的方法有startThread
、shutdownGracefully
和shutdown
。
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);
}
}
}
}
複製程式碼
startThread
執行緒未開始時,嘗試更新執行緒狀態為一開始,更新成功,則呼叫doStartThread
方法啟動執行緒,子類的run方法就是在這裡呼叫的,比如說接下來的NioEventLoop
。
shutdownGracefully
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
// 靜待時間需要>=0
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");
}
// 關閉中直接返回終止Future
if (isShuttingDown()) {
return terminationFuture();
}
boolean inEventLoop = inEventLoop();
boolean wakeup;
int oldState;
for (; ; ) {
// 關閉中直接返回終止Future
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 (oldState == ST_NOT_STARTED) {
try {
doStartThread();
} catch (Throwable cause) {
STATE_UPDATER.set(this, ST_TERMINATED);
terminationFuture.tryFailure(cause);
if (!(cause instanceof Exception)) {
PlatformDependent.throwException(cause);
}
return terminationFuture;
}
}
if (wakeup) {
wakeup(inEventLoop);
}
return terminationFuture();
}
複製程式碼
shutdownGracefully
目的是讓正在執行的任務再執行一會兒,同時拒絕新任務。quietPeriod
和timeout
這兩個時間會在confirmShutdown
方法中用到,當然單位已經轉為納秒了。
事件的執行
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
boolean inEventLoop = inEventLoop();
if (inEventLoop) {
addTask(task);
} else {
startThread();
addTask(task);
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
複製程式碼
NioEventLoop
NioEventLoop
的核心操作都在它的run方法裡面:
protected void run() {
for (; ; ) {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.SELECT:
// 重置wakenUp為false並選擇任務
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
default:
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
// 當處理io用時佔比為100%時
if (ioRatio == 100) {
try {
processSelectedKeys();
} finally {
runAllTasks();
}
} else {
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
// 處理Loop異常
handleLoopException(t);
}
try {
// 處於關閉狀態
if (isShuttingDown()) {
// 關閉所有
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
// 處理Loop異常
handleLoopException(t);
}
}
}
複製程式碼
該方法主要是處理流程的控制,包括選擇、處理和關閉這幾種。
文中帖的程式碼註釋全在:KAMIJYOUDOUMA, 有興趣的童鞋可以關注一下。
本篇到此結束,如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【貳級天災】,查閱更多精彩歷史!!!