概述
本文主要讲述netty bossGroup初始化相关流程
初始化
bossGroup实际类型是,NioEventLoopGroup,即然探究初始化流程,那么直接进入构造方法
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
在进行NioEventLoopGroup进行构造的时候,会不断的调用重载构造,最终调用的构造如上
nThreads:线程数
executor:这里传来的是null
selectorProvider:这个对象可以用来获取selector
selectStrategyFactory:选择策略,对应selector的选择策略
RejectedExecutionHandlers.reject():拒绝策略
继续深挖
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
}
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
然后就会调用其父类的构造方法,这里获取电脑的cpu数,如果开发人员没有传入nThread,那么默认线程数就是cpu*2
接着还会调用其父类构造,我们来直接看调用的尽头
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
...
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) {
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) {
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);
}
在上面所看到的构造器才真正的进行初始化操作
首先是给executor进行初始化 newDefaultThreadFactory() ,在这个类里面我们可以看到一个newThread 的方法,返回出来的是一个Thread对象,由此可见,newDafaultThreadFactory 主要是用来返回一个线程的,至于ThreadPerTaskExecutor这个类,无非是对线程工厂进行了一层包装,然后继承了Executor这个类,并重写了execute,说明,这个类是专门用来启动线程的
然后根据 nThread 来创建对应大小的数组
接着循环这个数组,调用newChild 为其赋值
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(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;
}
跟进到NioEventLoop 的构造 ,里面又调用了其父类的构造,我简单解释一下在这个父类构造里面做了那些事情
参数介绍:
parent:NioEventLoopGroup
executor:前面初始化过的线程池
false:先理解为就是一个标志位
DEFAULT_MAX_PENDING_TASKS:线程池的队列大小,可以通过系统参数设置
rejectedExecutionHandler:拒绝策略
简单的来说就是继续对线程池进行初始化,保存一下这个线程执行器,创建一个任务队列
接下来看一个比较重要的方法openSelector()
这个方法返回的是一个SelectorTuple对象 ,在这里面有两个selector对象
删除了一些不重要的代码
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
unwrappedSelector = provider.openSelector();
Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return Class.forName(
"sun.nio.ch.SelectorImpl",
false,
PlatformDependent.getSystemClassLoader());
}
});
final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;
//netty自定义的Set
final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
// Let us try to use sun.misc.Unsafe to replace the SelectionKeySet.
// This allows us to also do this in Java9+ without any extra flags.
long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);
long publicSelectedKeysFieldOffset =
PlatformDependent.objectFieldOffset(publicSelectedKeysField);
if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {
PlatformDependent.putObject(
unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);
PlatformDependent.putObject(
unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);
return null;
}
}
selectedKeysField.set(unwrappedSelector, selectedKeySet);
publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
return null;
} catch (NoSuchFieldException e) {
return e;
} catch (IllegalAccessException e) {
return e;
}
}
});
selectedKeys = selectedKeySet;
return new SelectorTuple(unwrappedSelector,
new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
这里首先调用了NIO的方法获取到了一个selector,随后获取SelectorImpl的class对象
在这个方法里面我们还能看到SelectedSelectionKeySet ,这是netty自定义的一个set集合,而netty获取SelectorImpl对象的目的,就是为了对这个返回的selector的属性进行替换,使用自定义的set使netty的性能进一步提升,随后就将替换后的selector和没有替换的selector(但是经过一层包装的selector)都封装在SelectorTuple这个对象返回
现在从这里回到MultithreadEventExecutorGroup里面,也就是说每一个NioEventLoop都保存着一个executor和一个Selector
接着就会将children传入newChooser这个方法,返回一个选择策略,这个选择策略就是用来选择NioEventLoop的策略
至此,NioEventLoopGroup的主要初始化流程完毕,主要就是创建了一个EventExecutor的数组,以及对线程池进行一些初始化的操作,替换selector的数据结构