NioEventLoopGroup其实就是reactor模式中的reactor的角色,本节我们先来看看NioEventLoopGroup在new的过程当中做了哪些事情
public NioEventLoopGroup(int nThreads,
ThreadFactory threadFactory,
final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads,
threadFactory,
selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
使用new创建NioEventLoopGroup时,会经过一系列构造方法调用,最终调用到上图中5个参数的构造方法,该构造方法会调用到父类MultithreadEventLoopGroup的构造方法,其中线程数如果不传,默认为cpu个数乘以2,源码如下
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);
}
上面代码中,会先生成一个执行器executor,ThreadPerTaskExecutor的构造函数接收一个DefaultThreadFactory类型的对象做为参数赋值给自己的成员变量threadFactory,该类中还有一个execute方法用来通过threadFactory对象生成一个线程对象并启动该线程,DefaultThreadFactory类实现了ThreadFactory接口,接口中只有一个newThread方法用来创建Thread对象
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();
}
}
public class DefaultThreadFactory implements ThreadFactory {
......
public DefaultThreadFactory(Class<?> poolType) {
this(poolType, false, Thread.NORM_PRIORITY);
}
......省去部分代发
}
接着生成了一个EventExecutor类型的数组children,其实该数组中存储的就是NioEventLoop对象
然后在for循环中做的最主要的事情就是根据线程个数,初始化children数组对象,而该对象的创建是在NioEventLoopGroup中,在newChild方法中通过new NioEventLoop完成对象的创建,NioEventLoop的构造方法如下:
public final class NioEventLoop extends SingleThreadEventLoop {
......
private Selector selector;//java nio中的选择器(多路复用器)
private Selector unwrappedSelector;
private SelectedSelectionKeySet selectedKeys;//选择键
private final SelectorProvider provider;//通过该类生成多路复用器Selector
......
//io线程和用户线程所占的比例
private volatile int ioRatio = 50;
......
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中设置了Selector和selectedKeys,学过java nio的都知道这是jdk的类,因为netty也是包装nio实现的框架,而nio又是Reactor模式的实现,Reactor模式后续单独讲,本章节只讲NioEventLoopGroup在创建时所做的事情,构造函数中,首先调用的父类SingleThreadEventLoop的构造函数,接着进行一下赋值操作,其中最重要的就是生成多路复用器Selector,通过调用openSelector()实现,如下
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
try {
unwrappedSelector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
......
}
MultithreadEventExecutorGroup中有如下一个成员属性,其中通过GlobalEventExecutor.INSTANCE的创建,完成了延迟队列
private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
private GlobalEventExecutor() {
//完成延迟队列的初始化
scheduledTaskQueue().add(quietPeriodTask);
threadFactory = ThreadExecutorMap.apply(new DefaultThreadFactory(
DefaultThreadFactory.toPoolName(getClass()), false, Thread.NORM_PRIORITY, null), this);
}
父类SingleThreadEventLoop的构造函数中友调用了自己的父类SingleThreadEventExecutor的构造函数,SingleThreadEventLoop完成了对tailTasks队列的初始化
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
......
private final Queue<Runnable> tailTasks;
......
protected SingleThreadEventLoop(EventLoopGroup parent,
Executor executor,
boolean addTaskWakesUp,
int maxPendingTasks,
RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, addTaskWakesUp, maxPendingTasks,rejectedExecutionHandler);
tailTasks = newTaskQueue(maxPendingTasks);
}
......
/**
* Create a new {@link Queue} which will holds the tasks to execute. This default implementation will return a
* {@link LinkedBlockingQueue} but if your sub-class of {@link SingleThreadEventExecutor} will not do any blocking
* calls on the this {@link Queue} it may make sense to {@code @Override} this and return some more performant
* implementation that does not support blocking operations at all.
*/
protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
}
.......
}
SingleThreadEventExecutor中的构造函数中,先调用了父类AbstractScheduledEventExecutor的构造函数,接着又调用了AbstractEventExecutor的构造函数,接着SingleThreadEventExecutor的构造函数中进行一些赋值操作,并创建了一个链表的阻塞队列taskQueue,该队列用于存储需要执行的任务
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
......
private final Queue<Runnable> taskQueue;
......
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 = ThreadExecutorMap.apply(executor, this);
taskQueue = newTaskQueue(this.maxPendingTasks);
rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler,
"rejectedHandler");
}
......
protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
}
}
上面由new NioEventLoop()对应的一系列构造方法操作完成后,第37行代码创建了一个EventExecutorChooserFactory.EventExecutorChooser的chooser对象,代码如下
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
......省略部分代码
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
//判断是不是2的n次方
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
private static final class PowerOfTwoEventExecutorChooser implements
EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
private static final class GenericEventExecutorChooser implements
EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
}
进入newChooser方法中,先通过isPowerOfTwo方法判断executors数组长度是不是2的n次方,这里需要注意的是(val & -val) == val,这种写法就是经典的2的n次方的判断方式,接着对不同条件有两种实现方式,而PowerOfTwoEventExecutorChooser和GenericEventExecutorChooser都持有了EventExecutor数组对象,并通过next从EventExecutor数组中取得NioEventLoop对象,所以其他类中要想从数组中获取NioEventLoop对象,都需要通过chooser对象都next方法获取
总结:
当我们创建NioEventLoopGroup对象都时候,主要做了如下几件事情
- 完成了线程池的初始化,并放到了EventExecutor类型的children数组对象中,该数组中的NioEventLoop对象通过chooser对象根据不同的算法获取
- 创建了Selector对象,并于NioEventLoop进行关联(是NioEventLoop的成员变量)
- 创建了两个阻塞队列tailTasks和taskQueue,其中taskQueue就是NioEventLoop执行任务所使用的队列
- 创建了EventExecutorChooserFactory.EventExecutorChooser类型的chooser对象,通过该对象的next方法从EventExecutor数组中获取