1. Inheritance system diagram of nioeventloopgroup
You can see that the EventExecutorGroup inherits from ScheduleExecutorService and Iterable
This means that there are thread pools and iterators. What does NioEventLoopGroup do to the thread pool and what are iterators iterating? Look down~
2. Function description of eventexecutorgroup core interface
As the core interface, EventExecutorGroup defines the basic core functions. So what does it do?
Official interpretation:
EventExecutorGroup is responsible for providing EventExecutor externally through its own next() method. Moreover, it is also responsible for handling the life cycle of these event executors and providing a global shutdown interface
As can be seen from the following method, EventExecutorGroup itself has the function of thread pool, and then internally maintains a collection of eventexecutors.
EventExecutor itself is inherited from EventExecutorGroup
It can be imagined that EventExecutorGroup is a thread pool group management tool that sets a set of thread pools
method:
/** * Check whether all eventexecutors managed by EventExecutorGroup have been gracefully closed. * Close all is true */ boolean isShuttingDown(); /** * Simple invocation of the {shutdown gracefully (long, long, timeunit)} method based on the default value */ Future<?> shutdownGracefully(); /** *Tell the executor that it needs to close. Once this method is called, the isShuttingDown() method starts to return true, and the executor is ready to close itself. * Unlike the shutdown() method, this is more elegant. It will have a closed silent period. If a task is submitted during this period, the silent period will be recalculated. * In general: * It will wait for a certain time before closing. If a task is submitted during this period, the waiting time will restart calculation */ Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit); /** * After all eventexecutors managed by the current EventExecutorGroup are closed, asynchronous callback will be performed */ Future<?> terminationFuture(); /** * This is a forced shutdown and is no longer recommended */ @Override @Deprecated void shutdown(); /** * This is a forced shutdown and is no longer recommended * */ @Override @Deprecated List<Runnable> shutdownNow(); /** * (Important methods) *Returns one of the many eventexecutors managed by the EventExecutorGroup. The selection method is determined by the subclass itself */ EventExecutor next(); /** * ================================================= * The following are the rewriting of the methods of scheduledexecutorservice and Iterable < eventexecutor > (well, lonely rewriting) * ================================================= */ @Override Iterator<EventExecutor> iterator(); @Override Future<?> submit(Runnable task); @Override <T> Future<T> submit(Runnable task, T result); @Override <T> Future<T> submit(Callable<T> task); @Override ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit); @Override <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit); @Override ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); @Override ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
3. Initialization of nioeventloopgroup
It initializes and turns more. Several default parameters are involved, which is worth thinking about.
It goes through multi-layer construction method calls here, and then enters the parent class construction MultithreadEventLoopGroup, where it makes multiple construction method calls again.
Several construction components are involved:
Executor : new ThreadPerTaskExecutor(newDefaultThreadFactory())
SelectorProvider: the default is SelectorProvider provider()
Selector.select() polling processing policy: defaultselectstrategyfactory INSTANCE
Thread pool queue full policy: rejectedexecutionhandlers reject()
EventExecutor selector: defaulteventexecutorchooserfactory INSTANCE
3.1 what is the default number of threads for NioEventLoopGroup?
io.netty.channel.MultithreadEventLoopGroup
private static final int DEFAULT_EVENT_LOOP_THREADS; static { // The default is cpu processor cores * 2 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); } }
3.2 core initialization
The following code mainly does two things:
Initialize your own EventExecutor thread pool collection (EventExecutor[] children)
The selector of NioEventLoopGroup for EventExecutor collection (EventExecutorChooserFactory.EventExecutorChooser) is initialized
By the way, we also built a read-only collection. I don't know what to do for the time being. I'll add it when I see it
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) { // Check whether nThreads is a positive number. The default is the number of cpu cores * 2 checkPositive(nThreads, "nThreads"); // If you do not need a customized thread pool, there is a default one-way thread pool if (executor == null) { // Thread pool initialization, no task queue // newDefaultThreadFactory is responsible for thread creation // FastThreadLocalThread executor = new ThreadPerTaskExecutor(newDefaultThreadFactory()); } // Create thread pool group children = new EventExecutor[nThreads]; for (int i = 0; i < nThreads; i ++) { boolean success = false; try { // Create NioEventLoop as an element of thread pool group management children[i] = newChild(executor, args); success = true; } catch (Exception e) { // Todo: think about if this is a good exception type eventexecutorinitializeexception? throw new IllegalStateException("failed to create a child event loop", e); } finally { if (!success) { for (int j = 0; j < i; j ++) { // Here J < I is very smart. You only need to close the NioEventLoop created before the exception children[j].shutdownGracefully(); } for (int j = 0; j < i; j ++) { EventExecutor e = children[j]; try { while (!e.isTerminated()) { // Waiting to close e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS); } } catch (InterruptedException interrupted) { // Let the caller handle the interruption. Thread.currentThread().interrupt(); break; } } } } } // The event executor selector means that when a request comes, how does NioEventLoopGroup select the event executor to execute the request chooser = chooserFactory.newChooser(children); // Terminate the listener and listen to whether the EventExecutor stops 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); // Read only EventExecutor collection readonlyChildren = Collections.unmodifiableSet(childrenSet); }
4. Summary
From the initialization of NioEventLoopGroup, we can see that it is actually used to manage a series of eventexecutors.
The following figure shows the basic component structure of NioEventLoopGroup