上一篇主要介紹了一下
EventLoopGroup
,本篇詳細看下它的成員EventLoop
。git
NioEventLoop
繼承自
SingleThreadEventLoop
,而
SingleThreadEventLoop
又繼承自
SingleThreadEventExecutor
。
SingleThreadEventExecutor
內部持有一個Thread對象,是
Netty
多線程的基礎。 能夠認爲, 一個
NioEventLoop
與一個特定的線程進行了綁定,而且在其生命週期內,綁定的線程都不會再改變。
從名字就能夠看出來,SingleThreadEventExecutor
是一個單線程事件執行器。主要作的事情就是線程的管理和事件的執行。github
SingleThreadEventExecutor
中定義了五種線程狀態:bash
/**
* 未開始
*/
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
。多線程
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
。oop
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
方法中用到,固然單位已經轉爲納秒了。ui
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
的核心操做都在它的run方法裏面:this
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);
}
}
}
複製代碼
該方法主要是處理流程的控制,包括選擇、處理和關閉這幾種。spa
文中帖的代碼註釋全在:KAMIJYOUDOUMA, 有興趣的童鞋能夠關注一下。線程
本篇到此結束,若是讀完以爲有收穫的話,歡迎點贊、關注、加公衆號【貳級天災】,查閱更多精彩歷史!!! netty