NioEventLoopGroup is a thread pool model for Netty’s Reactor model (Reactor).
NioEventLoopGroup class diagramCan say NioEventLoopGroup class inheritance system is very complicated, we need to clear the thing is, NioEventLoopGroup is a subclass of MultithreadEventLoopGroup, And the parent is MultithreadEventExecutorGroup MultithreadEventLoopGroup, it is the parent of the ExecutorService again looked up, the ExecutorService is a thread pool.
In the previous article, we created two NioEventLoopGroups to start a NettyServer. Let’s take a look at what the initialization process does for nioEventLoopGroups.
In the constructor of NioEventLoopGroup, by calling the superclass constructor, eventually in MultithreadEventExecutorGroup, created the Executor and a named EventExecutor array of children, The array size is nThreads.
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) { if (nThreads <= 0) { throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads)); } // Create an executor in the eventLoopGroup. This executor will create a thread for each channel to perform the corresponding task. As you will see later, If (executor == null) {// If ThreadFactory is defined in the constructor of NioEventLoopGroup, it will not be executed. Executor = new ThreadPerTaskExecutor(newDefaultThreadFactory())); } // The eventLoopGroup contains an array of eventExecutor, Each NioEventLoop contains an executor and a selector Children = new EventExecutor[nThreads]; for (int i = 0; i < nThreads; i ++) { boolean success = false; try { children[i] = newChild(executor, args); // create NioEventLoop 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); }Copy the code
The constructor of NioEventLoopGroup can specify the number of threads, as well as the thread factory, and give the thread pool a name. In the previous article, we used the specified thread factory to specify the thread pool name for bossGroup and workerGroup. This also makes it easy to view the number of threads in different thread pools through JVisualVM.
If the number of threads is not specified, Netty uses twice the number of logical cores on the server as the default number of threads.
NioEventLoopGroup#newChild() creates an array of nioEventLoops. NioEventLoopGroup is an executor, and NioEventLoop is an executor. Are there a lot of question marks in your mind? Take a look at the NioEventLoop class diagram:Take a look at the constructor for NioEventLoop:
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
EventLoopTaskQueueFactory queueFactory) {
super(parent, executor, false, newTaskQueue(queueFactory), newTaskQueue(queueFactory),
rejectedExecutionHandler);
this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");
this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");
final SelectorTuple selectorTuple = openSelector();
this.selector = selectorTuple.selector;
this.unwrappedSelector = selectorTuple.unwrappedSelector;
}
Copy the code
A NioEventLoopGroup contains an executor and an array of NIoEventLoops; A NioEventLoop contains a selector, a provider, both of which are provided in NIO in the JDK, and a taskQueue; NioEventLoopGroup and NioEventLoop are both executors themselves. OMG!!!
SingleThreadEventExecutor inside a thread, it is actually Netty an encapsulation of native threads, we can think that a NioEventLoop with a thread binding, and in the life cycle NioEventLoop, None of the bound threads will change.
The NioEventLoopGroup thread pool will handle client requests in detail.