Netty EventLoopGroup源码分析

179 阅读2分钟

这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

前言

image.png

一个简单的列子

EchoServer

public class EchoServer {
    static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));

    public static void main(String[] args) throws Exception {
        // Configure the server.
        // 创建EventLoopGroup   accept线程组 NioEventLoop
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // 创建EventLoopGroup   I/O线程组
        EventLoopGroup workerGroup2 = new NioEventLoopGroup(1);
        try {
            // 服务端启动引导工具类
            ServerBootstrap b = new ServerBootstrap();
            // 配置服务端处理的reactor线程组以及服务端的其他配置
            b.group(bossGroup, workerGroup2).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
                    .handler(new LoggingHandler(LogLevel.DEBUG)).childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline p = ch.pipeline();
                    p.addLast(new EchoServerHandler());
                }
            });
            // 通过bind启动服务
            ChannelFuture f = b.bind(PORT).sync();
            // 阻塞主线程,知道网络服务被关闭
            f.channel().closeFuture().sync();
        } finally {
            // 关闭线程组
            bossGroup.shutdownGracefully();
            workerGroup2.shutdownGracefully();
        }
    }
}

EchoServerHandler

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("收到数据:" + ((ByteBuf)msg).toString(Charset.defaultCharset()));
        ctx.fireChannelRead(msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

EventLoopGroup 源码

1. NioEventLoopGroup 类层次结构

EventLoopGroup.png NioEventLoopGroup核心的类继承关系:

NioEventLoopGroup –> MultithreadEventLoopGroup –> MultithreadEventExecutorGroup

2. NioEventLoopGroup实例化过程

image.png (1)在NioEventLoopGroup构造器调用: 1.1

public NioEventLoopGroup() {
    this(0);
}

1.2 这里设置了NioEventLoopGroup线程池中每个线程执行器默认是null(这里设置为null, 在后面的构造器中会判断,如果为null就实例化一个线程执行器)。

public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor) null);
}

1.3 设置线程池的SelectorProvider, 通过SelectorProvider.provider() 返回。

public NioEventLoopGroup(int nThreads, Executor executor) {
    this(nThreads, executor, SelectorProvider.provider());
}

1.3 重载的构造器中又传入了默认的选择策略工厂DefaultSelectStrategyFactory;

public NioEventLoopGroup(
        int nThreads, Executor executor, final SelectorProvider selectorProvider) {
    this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

1.4 调用父类MultithreadEventLoopGroup的构造器

public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                         final SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}

(2)在MultithreadEventLoopGroup构造器调用:

image.png

(3)MultithreadEventExecutorGroup的构造器:

image.png 这个构造器里面多传入了一个参数 DefaultEventExecutorChooserFactory.INSTANCE , 通过这个EventLoop选择器工厂可以实例化GenericEventExecutorChooser这个类, 这个类是EventLoopGroup线程池里面的EventLoop的选择器,调用GenericEventExecutorChooser.next() 方法可以从线程池中选择出一个合适的EventLoop线程。

下面就是MultithreadEventExecutorGroup的核心源码

/**
 * Create a new instance.
 *
 * @param nThreads          实例将使用的线程数
 * @param executor          将要使用的executor, 默认为null
 * @param chooserFactory    the {@link EventExecutorChooserFactory} to use.
 * @param args              arguments which will passed to each {@link #newChild(Executor, Object...)} call
 */
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                        EventExecutorChooserFactory chooserFactory, Object... args) {
    checkPositive(nThreads, "nThreads");
    //1.初始化线程池
    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;
                    }
                }
            }
        }
    }
    // 2.实例化线程工厂执行器选择器
    chooser = chooserFactory.newChooser(children);
    // 3.为每个EventLoop线程添加 线程终止监听器
    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);
    }
    // 4. 将children 添加到对应的set集合中去重
    Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);
}