引子
在上一篇文章中我们已经分析了Netty注册相关的逻辑,接下来再开看下NioEventLoopGroup这个类内部的相关构造。
NioEventLoopGroup
在之前的demo中第一行就是:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
这个NioEventLoopGroup类的构造函数最终实现如下:
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;
......
}
}
}
其中传入的参数Executor对象就是多线程中的线程池接口的实现类(关于这块内容我特定又回过头去看多线程相关的知识,具体可以看另外一篇关于java多线程的文章)。接着来看一开始这个线程池对象是空的,就开始创建ThreadPerTaskExecutor实例,
我们首先就从这个ThreadPerTaskExecutor对象开始分析。
ThreadPerTaskExecutor
这个类内部实现如下:
public final class ThreadPerTaskExecutor implements Executor {
private final ThreadFactory threadFactory;
public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
if (threadFactory == null) {
throw new NullPointerException("threadFactory");
}
this.threadFactory = threadFactory;
}
@Override
public void execute(Runnable command) {
threadFactory.newThread(command).start();
}
}
从代码就可以看出ThreadPerTaskExecutor就是一个一个实现了Executor线程池的实现类,
execute方法内部开始调用线程工厂的newThread方法创建线程。当后续执行线程工厂的execute方法时就会创建一个新的线程。
传入的参数是一个newDefaultThreadFactory实例,这个对象实现了ThreadFactory工厂接口,所以就是一个线程工厂类,它的构造函数实现如下:
public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
if (poolName == null) {
throw new NullPointerException("poolName");
}
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
throw ......
}
prefix = poolName + '-' + poolId.incrementAndGet() + '-';
this.daemon = daemon;
this.priority = priority;
this.threadGroup = threadGroup;
}
看到这我们先对上面的内容做个小结:
- 从这两段代码可以看出
ThreadPerTaskExecutor()
这个方法做的就是创建一个线程池,并且线程池的优先级为Thread.NORM_PRIORITY
,即5(优先级越大越优先执行,5是普通的优先级)。 - 每当new一个NioEventLoopGroup对象的时候,实际上内部就会先创建一个线程池。
newChild()方法分析
上面讲到executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
方法创建了一个线程池。接下来就执行了:
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
......
这个newChild方法实现如下:
@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(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;
selector = openSelector();
selectStrategy = strategy;
}
从源码中可以看出newChild方法创建了一个NioEventLoop对象。构造方法中除了给变量赋值外,又调了父类的构造方法,继续往下看:
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");
}
从这两部分看出newChild方法主要是创建了一个NioEventLoop对象,这个对象内部保存了provider,selector,selectStrategy以及一个taskQueue队列。这里的provider就是Java NIO中的选择器provider,selector就是选择器,至于这些东西具体是怎么用的,这里我还是疑惑的,要后面用到的地方继续分析了。
newChooser
接下来看NioEventLoopGroup构造函数的第三部分:
chooser = chooserFactory.newChooser(children);
这里传入的children数组就是上面讲到的创建的NioEventLoop数组,但是返回的这个chooser是个什么鬼,又不懂了,真是头疼~。所以这里先保留这个疑问吧,只能后续学习明白了再回头补了。