netty multithreaded event loop group

netty event executor group and event executor definition and abstract implementation: http://donald-draper.iteye.com/blog/2391257
netty multi-threaded event executor group: http://donald-draper.iteye.com/blog /2391270
Introduction:
In the previous article, we saw the multi-threaded event executor group, let's review it first:
     the multi-threaded event executor group MultithreadEventExecutorGroup, there is an event executor array inside to store the event executors in the group; readonlyChildren is the group The readable wrapper set of the event executor set; terminatedChildren (AtomicInteger), used to record the number of event executors that have been closed; termination is the executor group terminated asynchronous task result; at the same time, there is an event executor selector chooser (EventExecutorChooser). Construct a multi-threaded executor group, first check the thread number parameter, if the executor is not empty, initialize the thread factory of the thread executor, create an event executor set, and create an event executor according to the executor and related parameters, and actually create a method For newChild, to be implemented by subclasses, initialize the event executor selector, create the terminated event executor listener, add the terminated event executor listener to the terminated asynchronous task result, and wrap the event executor set as the read-only set readonlyChildren.
     Get the next event executor method of the executor group to delegate a memory event executor selector chooser; the returned iterator is the iterator of the internal read-only executor set; and the close executor group method is actually a traversal of managed events Executor set, close the executor; determine whether the executor group is closed and Terminated, if and only when the event executors in the group are closed and Terminated, it will return true; timeout waiting for the Terminated executor group method, which is actually traversal event execution Stop the Terminated executor group if the timeout waiting time of the executor group runs out, otherwise, the remaining waiting time timeLeft of the timeout, Terminated event executor.
I wanted to take a look at the multi-threaded event loop group in this article, but it implements the event loop group. Let's take a look at EventLoopGroup
//MultithreadEventLoopGroup first.
package io.netty.channel;

import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.EventExecutorChooserFactory;
import io.netty.util.concurrent.MultithreadEventExecutorGroup;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;

/**
 * Abstract base class for {@link EventLoopGroup} implementations that handles their tasks with multiple threads at
 * the same time.
 */
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {


Let's look at the definition of the event loop group EventLoopGroup
package io.netty.channel;

import io.netty.util.concurrent.EventExecutorGroup;

/**
 * Special {@link EventExecutorGroup} which allows registering {@link Channel}s that get
 * processed for later selection during the event loop.
 *
 */
public interface EventLoopGroup extends EventExecutorGroup {
    /**
     * Return the next {@link EventLoop} to use
     Return to the next event loop
     */
    @Override
    EventLoop next();

    /**
     * Register a {@link Channel} with this {@link EventLoop}. The returned {@link ChannelFuture}
     * will get notified once the registration was complete.
     Register the channel to the event loop, return the asynchronous channel registration result, and notify the result when the registration is complete.
     */
    ChannelFuture register(Channel channel);

    /**
     * Register a {@link Channel} with this {@link EventLoop} using a {@link ChannelFuture}. The passed
     * {@link ChannelFuture} will get notified once the registration was complete and also will get returned.
     Registers the channel associated with the writable asynchronous channel task result
     */
    ChannelFuture register(ChannelPromise promise);

    /**
     * Register a {@link Channel} with this {@link EventLoop}. The passed {@link ChannelFuture}
     * will get notified once the registration was complete and also will get returned.
     * Register the channel to the event loop, and when the registration is complete, notify the asynchronous channel of the registration result.
     * @deprecated Use {@link #register(ChannelPromise)} instead.
     */
    @Deprecated
    ChannelFuture register(Channel channel, ChannelPromise promise);
}

As can be seen from the above, the event loop group EventLoopGroup inherits the event executor group EventExecutorGroup, the next method returns the event loop EventLoop, and
the main work of the event loop group is channel registration.

Let's look at the definition of the event loop EventLoop interface:
//EventLoop
package io.netty.channel;

import io.netty.util.concurrent.OrderedEventExecutor;

/**
 * Will handle all the I/O operations for a {@link Channel} once registered.
 *
 * One {@link EventLoop} instance will usually handle more than one {@link Channel} but this may depend on
 * implementation details and internals.
 An event loop instance can handle multiple channels, depending on the specific implementation.
 *
 */
public interface EventLoop extends OrderedEventExecutor, EventLoopGroup {
   //Get the event loop group to which the event loop belongs
    @Override
    EventLoopGroup parent();
}
//OrderedEventExecutor
package io.netty.util.concurrent;

/**
 * Marker interface for {@link EventExecutor}s that will process all submitted tasks in an ordered / serial fashion.
 Flag an event executor to process submitted tasks in a sequential, serial fashion
 */
public interface OrderedEventExecutor extends EventExecutor {
}

It can be seen from the above that the event loop EventLoop can be understood as an event executor EventExecutor that processes submitted tasks in a sequential and serial manner. The event loop group EventLoopGroup can be understood as a special event executor group EventExecutorGroup; the event executor group manages the event executor, and the event loop group manages the event loop.

Let's look at the event loop abstraction implementation:

package io.netty.channel;

import io.netty.util.concurrent.AbstractEventExecutor;

/**
 * Skeletal implementation of {@link EventLoop}.
 */
public abstract class AbstractEventLoop extends AbstractEventExecutor implements EventLoop {
    protected AbstractEventLoop() { }
    protected AbstractEventLoop(EventLoopGroup parent) {
        super(parent);
    }
    @Override
    public EventLoopGroup parent() {
        return (EventLoopGroup) super.parent();
    }
    @Override
    public EventLoop next() {
        return (EventLoop) super.next();
    }
}

The abstract event loop AbstractEventLoop inherits the abstract event executor and implements the event loop interface.

Given that the event loop and event loop group have been read in this way, let's take a look at the multi-threaded event loop group:
package io.netty.channel;

import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.EventExecutorChooserFactory;
import io.netty.util.concurrent.MultithreadEventExecutorGroup;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;

/**
 * Abstract base class for {@link EventLoopGroup} implementations that handles their tasks with multiple threads at
 * the same time.
 */
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);

    private static final int DEFAULT_EVENT_LOOP_THREADS;//Number of default event loop threads

    static {
        //The default event loop thread count is 1 and the maximum of 2 times the number of available processors
        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);
        }
    }
    //The following constructors are specific to the corresponding structure of the multi-threaded event executor group
    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }
    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, ThreadFactory, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
    }
    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor,
     * EventExecutorChooserFactory, Object...)
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory,
                                     Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, chooserFactory, args);
    }

    @Override
    protected ThreadFactory newDefaultThreadFactory() {
        //The thread priority of the default thread factory created defaults to the maximum priority
        return new DefaultThreadFactory(getClass(), Thread.MAX_PRIORITY);
    }

    @Override
    public EventLoop next() {
        return (EventLoop) super.next();
    }
    //Create a transaction loop, to be implemented by subclasses
    @Override
    protected abstract EventLoop newChild(Executor executor, Object... args) throws Exception;

    @Override
    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }

    @Override
    public ChannelFuture register(ChannelPromise promise) {
        return next().register(promise);
    }

    @Deprecated
    @Override
    public ChannelFuture register(Channel channel, ChannelPromise promise) {
        return next().register(channel, promise);
    }
}

As can be seen from the above, the multi-threaded event loop group MultithreadEventLoopGroup inherits the multi-threaded event executor group and implements the event loop group interface. The
related registration channel method is delegated to the next event loop of the multi-threaded event loop group, and the thread created by the thread project has priority. The default is the maximum thread priority; the
default event loop thread number is the largest of 1 and 2 times the number of available processors, which is the number of event executors to construct a multi-threaded event executor group.


//NioEventLoopGroup
/**
 * {@link MultithreadEventLoopGroup} implementations which is used for NIO {@link Selector} based {@link Channel}s.
 */
public class NioEventLoopGroup extends MultithreadEventLoopGroup {
    ...
    @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]);
    }
}

From the event loop created by the Nio event loop group, it can be seen that the event loop is NioEventLoop, which is what the next article will read. First, the
Nio event loop declaration inheritance tree is listed.
/**
 * {@link SingleThreadEventLoop} implementation which register the {@link Channel}'s to a
 * {@link Selector} and so does the multi-plexing of these in the event loop.
 *
 */
public final class NioEventLoop extends SingleThreadEventLoop {

/**
 * Abstract base class for {@link EventLoop}s that execute all its submitted tasks in a single thread.
 *
 */
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {

/**
 * Abstract base class for {@link OrderedEventExecutor}'s that execute all its submitted tasks in a single thread.
 *
 */
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {


Summary:

     The event loop group EventLoopGroup inherits the event executor group EventExecutorGroup, the next method returns the event loop EventLoop, and the main work of the event loop group is channel registration.
     The event loop EventLoop can be understood as an event executor EventExecutor that processes submitted tasks in a sequential and serial manner. The event loop group EventLoopGroup can be understood as a special event executor group EventExecutorGroup; the event executor group manages the event executor, and the event loop group manages the event loop. The abstract event loop AbstractEventLoop inherits the abstract event executor AbstractEventExecutor and implements the event loop interface.
     The multithreaded event loop group MultithreadEventLoopGroup inherits the multithreaded event executor group and implements the event loop group interface. The related registration channel method is delegated to the next event loop of the multithreaded event loop group. The thread priority created by the thread project defaults to the maximum thread priority. level; the default number of event loop threads is the largest of 1 and 2 times the number of available processors, which is the number of event executors to construct a multi-threaded event executor group.

Attachment:
In the static statement of the multi-threaded event loop group, there is the following paragraph to initialize the default number of event loop threads:
private static final int DEFAULT_EVENT_LOOP_THREADS;//Number of default event loop threads
static {
    //The default event loop thread count is 1 and the maximum of 2 times the number of available processors
    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);
    }
}

Let's take a look at NettyRuntime

package io.netty.util;

import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.SystemPropertyUtil;

import java.util.Locale;

/**
 * A utility class for wrapping calls to {@link Runtime}.
 runtime wrapper class
 */
public final class NettyRuntime {
    // can use the handler holder
    private static final AvailableProcessorsHolder holder = new AvailableProcessorsHolder();
    /**
     * Holder class for available processors to enable testing.
     */
    static class AvailableProcessorsHolder {
        private int availableProcessors;//Number of available processors

        /**
         * Set the number of available processors.
         * Set the number of processors available
         * @param availableProcessors the number of available processors
         * @throws IllegalArgumentException if the specified number of available processors is non-positive
         * @throws IllegalStateException    if the number of available processors is already configured
         */
        synchronized void setAvailableProcessors(final int availableProcessors) {
            ObjectUtil.checkPositive(availableProcessors, "availableProcessors");
            if (this.availableProcessors != 0) {
                final String message = String.format(
                        Locale.ROOT,
                        "availableProcessors is already set to [%d], rejecting [%d]",
                        this.availableProcessors,
                        availableProcessors);
                throw new IllegalStateException(message);
            }
            this.availableProcessors = availableProcessors;
        }

        /**
         * Get the configured number of available processors. The default is {@link Runtime#availableProcessors()}.
         * This can be overridden by setting the system property "io.netty.availableProcessors" or by invoking
         * {@link #setAvailableProcessors(int)} before any calls to this method.
         *
         * @return the configured number of available processors
         */
        @SuppressForbidden(reason = "to obtain default number of available processors")
        synchronized int availableProcessors() {
            if (this.availableProcessors == 0) {
	        //Get the number of processors available to the system
                final int availableProcessors =
                        SystemPropertyUtil.getInt(
                                "io.netty.availableProcessors",
                                Runtime.getRuntime().availableProcessors());
                setAvailableProcessors(availableProcessors);
            }
            return this.availableProcessors;
        }
    }

    /**
     * Set the number of available processors.
     * Set the number of processors available
     * @param availableProcessors the number of available processors
     * @throws IllegalArgumentException if the specified number of available processors is non-positive
     * @throws IllegalStateException    if the number of available processors is already configured
     */
    @SuppressWarnings("unused,WeakerAccess") // this method is part of the public API
    public static void setAvailableProcessors(final int availableProcessors) {
        holder.setAvailableProcessors(availableProcessors);
    }

    /**
     * Get the configured number of available processors. The default is {@link Runtime#availableProcessors()}. This
     * can be overridden by setting the system property "io.netty.availableProcessors" or by invoking
     * {@link #setAvailableProcessors(int)} before any calls to this method.
     * Get the number of available processors configured, the default is Runtime#availableProcessors(). Before calling this method,
     This value can be overridden by setting the io.netty.availableProcessors property or #setAvailableProcessors(int).
     * @return the configured number of available processors
     */
    public static int availableProcessors() {
        return holder.availableProcessors();
    }

    /**
     * No public constructor to prevent instances from being created.
     */
    private NettyRuntime() {
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326298340&siteId=291194637