無論服務端或客戶端啟動時都用到了
NioEventLoopGroup
,從名字就可以看出來它是NioEventLoop
的組合,是Netty多執行緒的基石。
類結構
NioEventLoopGroup
繼承自MultithreadEventLoopGroup
,多提供了兩個方法setIoRatio
和rebuildSelectors
,一個用於設定NioEventLoop
用於IO處理的時間佔比,另一個是重新構建Selectors,來處理epoll空輪詢導致CPU100%的bug。這個兩個的用處在介紹NioEventLoop
的時候在詳細介紹。其它的方法都在介面中有定義,先看下EventExecutorGroup
。
EventExecutorGroup
EventExecutorGroup
繼承自ScheduledExecutorService
和Iterable
。這意味著EventExecutorGroup
擁有定時處理任務的能力,同時本身可以迭代。它提供的方法有:
/**
* 是否所有事件執行器都處在關閉途中或關閉完成
*/
boolean isShuttingDown();
/**
* 優雅關閉
*/
Future<?> shutdownGracefully();
Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit);
/**
* 返回執行緒池終止時的非同步結果
*/
Future<?> terminationFuture();
void shutdown();
List<Runnable> shutdownNow();
/**
* 返回一個事件執行器
*/
EventExecutor next();
複製程式碼
其中shutdown
和shutdownNow
被標記為過時,不建議使用。EventExecutorGroup
還重寫ScheduledExecutorService
介面的方法,用於返回自定義的Future
。
EventLoopGroup
EventLoopGroup
繼承自EventExecutorGroup
,它和EventExecutorGroup
想比多了註冊Channel
和ChannelPromise
,同時重新next方法返回EventLoop
。
MultithreadEventExecutorGroup
建立NioEventLoopGroup
時,最終都會呼叫MultithreadEventExecutorGroup
的構造方法。
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
// 執行緒數必須大於0
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
// 沒指定Executor就建立新的Executor
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
// 建立EventExecutor陣列
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i++) {
// 建立結果標識
boolean success = false;
try {
// 建立EventExecutor物件
children[i] = newChild(executor, args);
// 設定建立成功
success = true;
} catch (Exception e) {
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
// 建立失敗,關閉所有已建立的EventExecutor
if (!success) {
// 關閉所有已建立的EventExecutor
for (int j = 0; j < i; j++) {
children[j].shutdownGracefully();
}
// 確保所有已建立的EventExecutor已關閉
for (int j = 0; j < i; j++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
// 建立EventExecutor選擇器
chooser = chooserFactory.newChooser(children);
// 建立監聽器,用於EventExecutor終止時的監聽
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
// 當EventExecutor全部關閉時
if (terminatedChildren.incrementAndGet() == children.length) {
// 設定結果,並通知監聽器們。
terminationFuture.setSuccess(null);
}
}
};
// 給每個EventExecutor新增上監聽器
for (EventExecutor e : children) {
e.terminationFuture().addListener(terminationListener);
}
// 建立只讀的EventExecutor集合
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
複製程式碼
整個構造方法做的就是EventExecutor
的建立,包括建立的異常處理,成功通知等。
AbstractEventExecutorGroup
、MultithreadEventLoopGroup
和NioEventLoopGroup
內部沒有特殊之處,就不擴充了。
文中帖的程式碼註釋全在:KAMIJYOUDOUMA, 有興趣的童鞋可以關注一下。
本篇到此結束,如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【貳級天災】,查閱更多精彩歷史!!!