在创建bossGroup和workGroup的时候,会用到NioEventLoopGroup对象,顾名思义,是NioEventLoop的集合,如何循环,如何使用。分析源码 如下
1、查看NioEventLoopGroup的继承关系图:
实现了两个接口,Exector和Iterable ,其中AbstractEventExecutorGroup重写了execute方法,循环执行NioEventLoop的run方法。
@Override public void execute(Runnable command) { //循环执行NioEventLoopGroup中的NioEventLoop的execute方法 ,最终会调用到io.netty.util.concurrent.SingleThreadEventExecutor#execute(java.lang.Runnable, boolean)方法,也就是循环组的Loop意义所在 next().execute(command); }
2.构造函数
io.netty.util.concurrent.MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, java.util.concurrent.Executor, io.netty.util.concurrent.EventExecutorChooserFactory, java.lang.Object...) 查看构造函数,实现如下功能
1. 创建每线程任务执行器
2.创建事件循环组的组员 :children数组,实例化每一个children对象
3.创建EventExecutorChooser选择器 可循环调用children数组中的对象
4.给children对象挨个添加监听事件,回调使用
5.给readonlyChildren赋值,通过迭代器遍历children数组
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) { ... if (executor == null) { //创建每一个线程任务执行器 executor = new ThreadPerTaskExecutor(newDefaultThreadFactory()); } //创建child的数组 下面会挨个赋值 children = new EventExecutor[nThreads]; for (int i = 0; i < nThreads; i ++) { boolean success = false; try { children[i] = newChild(executor, args);//创建EventLoop 参数executor 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; } } } } } //创建选择器 如果size是2的倍数 就与运算取模 否则除数取模 next作用就是获取下一个EventLoop //线程组 会通过chooser找到对应的下一个处理线程 chooser = chooserFactory.newChooser(children); final FutureListener<Object> terminationListener = new FutureListener<Object>() { @Override public void operationComplete(Future<Object> future) throws Exception {//回调方法operationComplete if (terminatedChildren.incrementAndGet() == children.length) { terminationFuture.setSuccess(null); } } }; for (EventExecutor e: children) {//每一个EventLoop都添加监听事件 e.terminationFuture().addListener(terminationListener); } Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length); Collections.addAll(childrenSet, children); readonlyChildren = Collections.unmodifiableSet(childrenSet); }
3.io.netty.util.concurrent.MultithreadEventExecutorGroup#newChild方法 创建group的组员信息
实现方法在io.netty.channel.nio.NioEventLoopGroup#newChild
protected EventLoop newChild(Executor executor, Object... args) throws Exception { SelectorProvider selectorProvider = (SelectorProvider) args[0]; SelectStrategyFactory selectStrategyFactory = (SelectStrategyFactory) args[1]; RejectedExecutionHandler rejectedExecutionHandler = (RejectedExecutionHandler) args[2]; EventLoopTaskQueueFactory taskQueueFactory = null; EventLoopTaskQueueFactory tailTaskQueueFactory = null; int argsLength = args.length; if (argsLength > 3) { taskQueueFactory = (EventLoopTaskQueueFactory) args[3]; } if (argsLength > 4) { tailTaskQueueFactory = (EventLoopTaskQueueFactory) args[4]; } //创建NioEventLoop return new NioEventLoop(this, executor, selectorProvider, selectStrategyFactory.newSelectStrategy(), rejectedExecutionHandler, taskQueueFactory, tailTaskQueueFactory); }
返回的是NioEventLoop对象 查看NioEventLoop的继承关系图 它也实现了Executor接口,在io.netty.util.concurrent.SingleThreadEventExecutor#execute(java.lang.Runnable, boolean)中重写了该方法
4.ioEventLoop的构造函数
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler, EventLoopTaskQueueFactory taskQueueFactory, EventLoopTaskQueueFactory tailTaskQueueFactory) { //继续调用父类的构造方法 最终调用到SingleThreadEventExecutor super(parent, executor, false, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory), rejectedExecutionHandler); this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider"); this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy"); final SelectorTuple selectorTuple = openSelector();//获取Selector选择器 this.selector = selectorTuple.selector; this.unwrappedSelector = selectorTuple.unwrappedSelector; }
查看父类的构造方法io.netty.util.concurrent.SingleThreadEventExecutor#SingleThreadEventExecutor(io.netty.util.concurrent.EventExecutorGroup, java.util.concurrent.Executor, boolean, java.util.Queue<java.lang.Runnable>, io.netty.util.concurrent.RejectedExecutionHandler)
protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp, Queue<Runnable> taskQueue, RejectedExecutionHandler rejectedHandler) { super(parent); this.addTaskWakesUp = addTaskWakesUp; this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS; //通过MultithreadEventExecutorGroup的构造函数中创建出来的executor对象创建了新的executor //this是 NioEventLoop 对象 this.executor = ThreadExecutorMap.apply(executor, this); //保存了任务队列 this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue"); //拒绝策略 this.rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler"); }
io.netty.channel.nio.NioEventLoop#openSelector 开启选择器 也就是用SelectorTuple对象包装了原生nio的selector对象
查看io.netty.util.concurrent.DefaultEventExecutorChooserFactory#newChooser 选择器方法
数组是2的倍数就与运算取模 否则就余运算取模
public EventExecutorChooser newChooser(EventExecutor[] executors) { if (isPowerOfTwo(executors.length)) {//如果是2的倍数 return new PowerOfTwoEventExecutorChooser(executors);//与运算获取next } else { return new GenericEventExecutorChooser(executors);//取余数取模 } }
我们debug调试代码发现 无论bossGroup还是workerGroup 结构都如下:
1.children就是组员信息 每一个对象都是NioEventLoop对象
2. defaultPromise对象 nio都是异步操作 需要future对象阻塞获取异步返回结果,在全局变量中直接赋值创建 后续分析
3. chooser选择器 挨个循环获取children的对象信息
children中的每一个NioEventLoop中包含了
1.selector 多路复用器
2.taskQueue 任务队列
3.executor执行器
后续再NioEventLoop的run方法中都会被用到
简单总结:
1.NioEventLoopGroup即创建线程组 bossGroup就是创建一个boss的线程 workGroup会创建指定个数|默认个数的线程
2.每一个线程对象是通过chooser对象来关联的 可以通过chooser对象指定异步任务交给组中下一个线程去处理
3.每一个NioEventLoop都包含了一个selector多路复用器 bossGroup用来监听OP_ACCEPT事件,当事件发生之后,获取到NioSocketChannel对象交给workGroup的线程异步去处理