NioEventLoop
首先我们先来了解一下NioEventLoop
NioEventLoopGroup就是一组NioEventLoop,而NioEventLoop又继承了Executor。因此,NioEventLoop本身实际上就是一个Executor。
我们可以在源码中找到它的 execute() 方法
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);
}
}
该方法存在于其父类SingleThreadEventExecutor,并且其代码根据netty的版本会有所不同。
注意看上面的代码,其中有一句startThread();,而跟进去之后最终会跟到doStartThread() 方法里
private void doStartThread() {
assert thread == null;
executor.execute(...省略...);
}
这里我们发现一个executor成员变量,也就意味着,不仅NioEventLoop是一个Executor,并且它里面也存在着一个Executor。因此,NioEventLoop有两个execute() 方法。
NioEventLoopGroup
NioEventLoopGroup也是继承了Executor。因此,NioEventLoopGroup也是一个Executor,并且NioEventLoopGroup内部也有一个成员变量executor。因此,NioEventLoopGroup也有两个execute() 方法。
NioEventLoopGroup初始化
这里我们从无参构造开始,一路往下跟(具体就省略了),直接跟到这个方法:
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (executor == null) {
// 这个executor是group的executor,将来会为每个eventLoop创建一个线程
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
//如果出现异常则会关闭掉所有已经创建好的eventLoop,并终止所有eventLoop上执行的任务
}
}
//创建选择器
chooser = chooserFactory.newChooser(children);
//下面还有很多代码,但是不重点分析了
}
为了方便阅读,我把本次分析不涉及到的代码先删掉了
首先看一下这个构造器涉及到的几个参数(从无参构造开始):
- nThreads : 线程数量,默认为cpu逻辑核心数两倍
- executor : 这个group所包含的executor
- selectorProvider : 用于提供selector及selectable的channel
- selectStrategyFactory : 选择策略工厂实例
逐行分析
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
当executor为空时,会先创建默认线程工厂,然后再创建线程executor对象。
这里的 executor 是NioEventLoopGroup 里的 Executor ,并不是指自己。
children = new EventExecutor[nThreads];
接下来创建了一个children数组,长度为线程数量。
因为NioEventLoopGroup是一组NioEventLoop,因此这里的children实际上是一组NioEventLoop。
接下来跟进newChild() 方法:
children[i] = newChild(executor, args);
=========================================================================
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
//这里将args参数强转了
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
=========================================================================
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
provider = selectorProvider;
// 创建一个selector的二元组
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
unwrappedSelector = selectorTuple.unwrappedSelector;
selectStrategy = strategy;
}
首先看父类构造:
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
========================================================================
protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
//创建一个收尾队列
tailTasks = newTaskQueue(maxPendingTasks);
}
========================================================================
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
boolean addTaskWakesUp, Queue<Runnable> taskQueue,
RejectedExecutionHandler rejectedHandler) {
super(parent);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS;
this.executor = ThreadExecutorMap.apply(executor, this);
//创建一个任务队列
this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue");
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
这里重点关注这行代码:
this.executor = ThreadExecutorMap.apply(executor, this);
这里this.executor是当前eventLoop里面的executor,而作为参数里面的executor则是前面 NioEventLoopGroup 构造方法一直传过来的的默认 Executor,我们继续往下看,看这个eventLoop里面的executor是怎么完成初始化的:
public static Executor apply(final Executor executor, final EventExecutor eventExecutor) {
//这个executor就是eventLoop的executor
return new Executor() {
@Override
public void execute(final Runnable command) {
executor.execute(apply(command, eventExecutor));
}
};
}
=========================================================================
public static Runnable apply(final Runnable command, final EventExecutor eventExecutor) {
return new Runnable() {
@Override
public void run() {
setCurrentEventExecutor(eventExecutor);
try {
//注意一下,这里是run方法
command.run();
} finally {
setCurrentEventExecutor(null);
}
}
};
}
从这里可以看出,eventLoop创建executor实际上就是再调用传过来的executor的方法(也就是NioEventLoopGroup的executor成员的executor方法,就是默认的executor方法),也就是说,这里执行的executor里的代码实际上是NioEventLoopGroup的executor成员的executor方法。
并且在执行的时候先会记录当前线程信息,并且在执行完成后删掉。
回到newChild方法,看openSelector()
先来看一个内部类SelectorTuple
private static final class SelectorTuple {
final Selector unwrappedSelector;
final Selector selector;
SelectorTuple(Selector unwrappedSelector) {
this.unwrappedSelector = unwrappedSelector;
this.selector = unwrappedSelector;
}
SelectorTuple(Selector unwrappedSelector, Selector selector) {
this.unwrappedSelector = unwrappedSelector;
this.selector = selector;
}
}
可以看到,SelectorTuple类里面有两个selector,用于封装优化前和优化后的selector,而openSelector() 方法就是根据配置判断是否优化当前的selector。
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
//根据provider创建出一个nio原生selector
unwrappedSelector = provider.openSelector();
//如果禁用了keySet优化则直接返回原生的selector
if (DISABLE_KEY_SET_OPTIMIZATION) {
return new SelectorTuple(unwrappedSelector);
}
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
//具体的优化过程
}
}
这里只需知道,openSelector() 方法先是创建一个原生的selector,然后查看配置,若是禁用了keySet优化则直接就返回原生selector,否则尽心优化后再返回。
总结:
1.NioEventLoopGroup和EventLoopGroup一样,既是一个executor,里面有execute方法,同时里面还包含着一个executor成员变量,也有一个execute方法。
2. 首先根据指定线程数创建相应数量的eventLoop,默认为逻辑核心数的2倍。
3. 创建 eventLoop 主要是先创建一个收尾队列和一个任务队列,然后将默认的 executor 传给 eventLoop 的 executor 并让其运行,然后根据配置判断需不需要优化创建的 selector。