创建NioEventLoopGroup
NioEventLoopGroup提供了很多构造方法,下面以参数最完整的构造方法为例:
public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory,
final SelectorProvider selectorProvider, final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, threadFactory, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
public NioEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory,
final RejectedExecutionHandler rejectedExecutionHandler) {
super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory, rejectedExecutionHandler);
}
参数含义:
nThreads:用于处理I/O请求的线程数量,可通过参数io.netty.eventLoopThreads进行配置,默认值为CPU核心数的两倍。
executor:与threadFactory只能存在其一,都是用于创建并启动I/O线程,executor为null则默认为ThreadPerTaskExecutor的实例,并使用DefaultThreadFactory创建该实例。
threadFactory:用于创建并启动I/O线程,最终也会使用该参数创建ThreadPerTaskExecutor的实例。调用具有该参数的构造器时,threadFactory不能为null。
selectorProvider:Selector的提供者,具体依赖底层实现,默认为SelectorProvider.provider()返回值。
selectStrategyFactory:SelectStrategy的实例化工厂,默认为DefaultSelectStrategyFactory。
chooserFactory:注册Channel时,需要从NioEventLoopGroup中选择一个EventLoop与Channel绑定。通过实现EventExecutorChooserFactory,重写newChooser,传入自定义的EventExecutorChooser即可自定义选择规则,默认为DefaultEventExecutorChooserFactory。
rejectedExecutionHandler:当超过EventLoop最大待处理任务数时,EventLoop拒绝处理任务的策略。实现RejectedExecutionHandler可定制化自己的拒绝策略。默认为RejectedExecutionHandlers.reject(),即抛出异常RejectedExecutionException。
NioEventLoopGroup比较常用的是无参构造器和传入线程数量的构造器,最终都是调用如下构造方法:
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
其中executor为null,selectorProvider、selectStrategyFactory、rejectedExecutionHandler等都为默认值,接下来调用父类MultithreadEventLoopGroup的构造方法:
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
nThreads为0则使用默认I/O线程数量,继续调用父类MultithreadEventExecutorGroup的构造方法:
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
if (executor == null) {
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 {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
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;
}
}
}
}
}
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
实例化过程:
- nThreads必须大于0,否则抛出异常;
- executor为null,则使用DefaultThreadFactory实例构造一个ThreadPerTaskExecutor实例作为executor,后续用该executor启动I/O线程;
- 初始化EventExecutor数组children,并循环调用newChild创建指定数量的NioEventLoop;
- 如果success为false,说明调用newChild抛出异常,终止实例化过程,调用shutdownGracefully优雅的关闭已经创建的NioEventLoop,并终止对应的线程;
- 如果最终全部NioEventLoop实例都正常创建,实例化chooser,后续调用next选择NioEventLoop实例将委托给该chooser完成;
- 为EventExecutor数组中的每个成员注册终止事件的监听器,当某个NioEventLoop实例对应的线程被终止时,自动通知监听者,当所有的I/O线程都被终止后,terminationFuture会被设置为success,并通知关心NioEventLoopGroup终止事件的监听者;
- 为children数组维护一个只读视图readonlyChildren,主要用于迭代。
到此,NioEventLoopGroup对象构造完成,下面分析newChild创建NioEventLoop的过程。
创建NioEventLoop
newChild的实现在NioEventLoopGroup中,源码如下:
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
下面进入NioEventLoop的构造方法:
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
if (selectorProvider == null) {
throw new NullPointerException("selectorProvider");
}
if (strategy == null) {
throw new NullPointerException("selectStrategy");
}
provider = selectorProvider;
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
unwrappedSelector = selectorTuple.unwrappedSelector;
selectStrategy = strategy;
}
由构造方法的参数可知,NioEventLoopGroup中提供的参数主要都用于构造NioEventLoop实例。作为NIO框架的Reactor线程,NioEventLoop需要处理网络I/O事件,因此必须聚合一个多路复用器对象,构造方法中主要完成该工作,后续详细分析。下面看父类SingleThreadEventLoop的构造方法:
protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
tailTasks = newTaskQueue(maxPendingTasks);
}
内部维护了一个tailTasks队列,目前没用。继续看父类SingleThreadEventExecutor的构造方法。
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
boolean addTaskWakesUp, int maxPendingTasks,
RejectedExecutionHandler rejectedHandler) {
super(parent);
this.addTaskWakesUp = addTaskWakesUp;
this.maxPendingTasks = Math.max(16, maxPendingTasks);
this.executor = ObjectUtil.checkNotNull(executor, "executor");
taskQueue = newTaskQueue(this.maxPendingTasks);
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}
参数含义:
parent:当前NioEventLoop所属的NioEventLoopGroup,最终会调用AbstractEventExecutor的构造方法完成parent的赋值;
addTaskWakesUp:是否在调用addTask(Runnable)时唤醒执行器线程,这里被设置为false;
executor:用于创建并启动I/O线程;
maxPendingTasks:最大待处理的任务数,当超过该值时,新加入的任务将会被拒绝;用户可通过参数io.netty.eventLoop.maxPendingTasks进行配置,不能小于16,默认为Integer.MAX_VALUE;
rejectedHandler:任务拒绝策略。
由构造方法可知,创建了一个具有maxPendingTasks数量的taskQueue,用于保存待处理的任务,该队列默认为LinkedBlockingQueue。
到此,NioEventLoop构造完成,下面分析NioEventLoop中多路复用器的创建过程。
创建Selector
NioEventLoop在openSelector()创建Selector对象,代码有点冗长,一步步分析,看实现:
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
try {
unwrappedSelector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
if (DISABLE_KEYSET_OPTIMIZATION) {
return new SelectorTuple(unwrappedSelector);
}
......
return new SelectorTuple(unwrappedSelector,
new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
首先调用SelectorProvider的openSelector()创建并打开一个新的Selector对象。Netty对Selector的SelectKeys进行了优化,用户可以通过io.netty.noKeySetOptimization开关决定是否启用该优化项,默认是关闭的,此时会创建一个SelectorTuple直接返回,selector和unwrappedSelector 都指向同一个Selector对象。
如果用户开启了SelectKeys的优化功能,继续执行:
private SelectorTuple openSelector() {
......
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
return Class.forName( "sun.nio.ch.SelectorImpl",false,
PlatformDependent.getSystemClassLoader());
} catch (Throwable cause) {
return cause;
}
}
});
if (!(maybeSelectorImplClass instanceof Class) ||
// ensure the current selector implementation is what we can instrument.
!((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) {
if (maybeSelectorImplClass instanceof Throwable) {
Throwable t = (Throwable) maybeSelectorImplClass;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);
}
return new SelectorTuple(unwrappedSelector);
}
......
return new SelectorTuple(unwrappedSelector,
new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
创建一个SelectedSelectionKeySet实例,用于保存SelectKey,内部主要定义了reset方法,用于从start位置开始,将后面的元素全部置为null,size置为0。SelectedSelectionKeySet功能类似一个简版的list,内部持有一个数组,并实现了自动扩容的功能,但诸如remove、contains、iterator等均不支持。为什么要扩展AbstractSet变成Set呢?后面解释。
加载sun.nio.ch.SelectorImpl的Class对象,并判断该Class对象与unwrappedSelector对应Class对象相等,若不相等或加载过程中返回无效的Class对象,创建一个SelectorTuple直接返回。
如果成功加载了正确的Class对象,继续向下执行:
private SelectorTuple openSelector() {
......
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField);
if (cause != null) {
return cause;
}
cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField);
if (cause != null) {
return cause;
}
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
return null;
} catch (NoSuchFieldException e) {
return e;
} catch (IllegalAccessException e) {
return e;
}
}
});
if (maybeException instanceof Exception) {
selectedKeys = null;
Exception e = (Exception) maybeException;
logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);
return new SelectorTuple(unwrappedSelector);
}
selectedKeys = selectedKeySet;
logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);
return new SelectorTuple(unwrappedSelector,
new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
此部分代码主要是通过反射的手段从Selector实例中获取publicKeys和publicSelectedKeys,修改这两个属性的访问权限为可写,然后使用Netty构造的SelectKeys包装对象selectedKeySet将JDK中的publicKeys和publicSelectedKeys替换掉。
此过程中若发生异常,创建一个SelectorTuple直接返回。否则,使用unwrappedSelector和包装类SelectedSelectionKeySetSelector的对象创建一个SelectorTuple返回。
由于Selector实例中publicKeys和publicSelectedKeys均为Set类型,因此SelectedSelectionKeySet为了兼容也被设计为Set。
到此,Selector的初始化过程介绍完了。
来源:oschina
链接:https://my.oschina.net/xiaominmin/blog/3509695