对于NioEventLoopGroup我的理解它就是一个线程池,它内部维护了一些线程,用于处理Channel上的事件。
NioEventLoopGroup主要功能就是为了创建一定数量的NioEventLoop,而真正的重点就在NioEventLoop中,它是整个netty线程执行的关键
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
这行代码干了什么,进入源码看一看
NioEventLoopGroup 源码如下↓
public class NioEventLoopGroup extends MultithreadEventLoopGroup {
/**
* 第一步我们使用的是无参构造所以我们从这开始
* 创建一个新的实例使用默认的线程数量
*/
public NioEventLoopGroup() {
this(0);
}
/**
* 第二步
* 指定线程为0,Executor为null
*/
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
/**
* 第三步
* 这个构造方法它会指定selector的辅助类 "SelectorProvider.provider()
*/
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
/**
* 第四步
* 初始化了一个默认的选择策略工厂,用于生成select策略
*/
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
/**
* 第五步
* 调用了父类 MultithreadEventLoopGroup
* 指定拒绝策略:RejectedExecutionHandlers.reject()
*/
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
}
//返回一个EventLoop ,即一个线程
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
EventLoopTaskQueueFactory queueFactory = args.length == 4 ? (EventLoopTaskQueueFactory) args[3] : null;
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2], queueFactory);
}
MultithreadEventLoopGroup的源码如下↓
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);
private static final int DEFAULT_EVENT_LOOP_THREADS;
/**
*静态代码块初始化了 DEFAULT_EVENT_LOOP_THREADS的值 ,值为 CPU核心数 * 2
*/
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
if (logger.isDebugEnabled()) {
logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
}
}
/**
* 当指定的线程数为0时,使用默认的线程数DEFAULT_EVENT_LOOP_THREADS
* 而DEFAULT_EVENT_LOOP_THREAD是在上面的静态代码块中就被执行
* 此处调用了父类MultithreadEventExecutorGroup的构造方法
*/
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
MultithreadEventExecutorGroup的源码如下↓
public abstract class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
private final EventExecutor[] children;
private final Set<EventExecutor> readonlyChildren;
private final AtomicInteger terminatedChildren = new AtomicInteger();
private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
private final EventExecutorChooserFactory.EventExecutorChooser chooser;
/**
*指定了一个EventExecutor的选择工厂DefaultEventExecutorChooserFactory,
*用于选择下一个可用的EventExecutor
*/
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args){
this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}
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校验非空, 如果为空就创建ThreadPerTaskExecutor, 该类实现了 Executor接口
// 这个executor 是用来执行线程池中的所有的线程,也就是所有的NioEventLoop,其实从
//NioEventLoop构造器中也可以知道,NioEventLoop构造器中都传入了executor这个参数。
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//这里的children数组, 其实就是线程池的核心实现,线程池中就是通过指定的线程数组来实现线程池;
//数组中每个元素其实就是一个EventLoop,EventLoop是EventExecutor的子接口。
//children数组,就是线程池的核心实现,线程池中就是通过指定的线程数组来实现线程池
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
//返回的是一个 NioEventLoop,就是给children数组中的每个元素指定了一个NioEventLoop实例
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);
}
}
总结如下:
1-NioEventLoopGroup初始化时如果未指定线程数,那么会使用默认线程数,即 线程数 = CPU核心数 * 2
2-每个NioEventLoopGroup对象内部都有一组可执行的NioEventLoop数组
,其大小是 nThreads, 这样就构成了一个线程池, 一个NIOEventLoop可以理解成就是一个线程
3-当有IO事件来时,需要从线程池中选择一个线程出来执行,这时候的NioEventLoop选择策略是由GenericEventExecutorChooser实现的,并调用该类的next()方法