Netty源码解析(二) —— NioEventLoopGroup(boss worker线程模型)

Netty的源码里面有example,参照echo demo启动netty服务

public final class EchoServer {

    static final boolean SSL = System.getProperty("ssl") != null;
    static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));

    public static void main(String[] args) throws Exception {
        // Configure SSL.
        final SslContext sslCtx;
        if (SSL) {
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
        } else {
            sslCtx = null;
        }

        //创建boss worker线程
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        final EchoServerHandler serverHandler = new EchoServerHandler();
        try {
            //创建netty服务端启动器
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)//给启动器配置boss worker
             .channel(NioServerSocketChannel.class)//设置使用NioServerSocketChannel
             .option(ChannelOption.SO_BACKLOG, 100)
             .handler(new LoggingHandler(LogLevel.INFO))
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
                         p.addLast(sslCtx.newHandler(ch.alloc()));
                     }
                     //p.addLast(new LoggingHandler(LogLevel.INFO));
                     p.addLast(serverHandler);
                 }
             });

            // Start the server.
            ChannelFuture f = b.bind(PORT).sync();

            // Wait until the server socket is closed.
            f.channel().closeFuture().sync();
        } finally {
            // Shut down all event loops to terminate all threads.
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

可以看到创建启动服务,创建了EventLoopGroup bossGroup = new NioEventLoopGroup(1),那么我们先来看看NioEventLoopGroup的源码
这里写图片描述
上图红线圈住的就是NioEventLoopGroup的继承体系,下面来分析NioEventLoopGroup的创建过程

    /**
     * 默认的无参构造会调用参数是0的构造
     */
    public NioEventLoopGroup() {
        this(0);

    public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
        this(nThreads, threadFactory, SelectorProvider.provider());
    }

    public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                             final SelectStrategyFactory selectStrategyFactory) {
         //调用父类构造
        super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
    }

MultithreadEventLoopGroup的构造

    /**
     * @see MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, Executor, Object...)
     * 如果传进来的nThreads==0 就用 DEFAULT_EVENT_LOOP_THREADS
     */
    protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
        super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
    }

DEFAULT_EVENT_LOOP_THREADS 是什么呢?

    private static final int DEFAULT_EVENT_LOOP_THREADS;

    static {
        //cpu核数*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);
        }
    }

在进入父类MultithreadEventExecutorGroup

    protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }

        //创建线程执行器,ThreadPerTaskExecutor的参数ThreadFactory适用于提供生产线程的工厂,
        //每次执行任务都会创建一个线程实体
        if (executor == null) {
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
        //boss或者worker内部的具体执行者
        children = new EventExecutor[nThreads];

        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                //创建work的eventLoop
                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 {
               .....
            }
        }

        /**
         * 创建线程选择器
         *                          NioEventLoop(work) 新来一个连接 index++
         * NioEventLoop(boss)     0     1     2      3      4
         *                       →
         *
         *                       线程选择器的优化,如果NioEventLoop(work) 线程个数是2的幂  2   4   8  16
         *                       那么返回一个PowerOfTwoEventExecutorChooser  否则  GenericEventExecutorChooser
         *
         *                          index++ & (len-1)                                index++ % (len-1)
         */
        chooser = chooserFactory.newChooser(children);

     .....
    }

ThreadPerTaskExecutor的创建

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        if (threadFactory == null) {
            throw new NullPointerException("threadFactory");
        }
        this.threadFactory = threadFactory;
    }

    /**
     * 创建线程,执行runnable代码块
     * @param command
     */
    @Override
    public void execute(Runnable command) {
        threadFactory.newThread(command).start();
    }
}

ThreadFactory 的newThread:

    /**
     * @param poolType NioEventLoopGroup
     * @return   返回的    nioEventLoopGroup
     */
    public static String toPoolName(Class<?> poolType) {
        if (poolType == null) {
            throw new NullPointerException("poolType");
        }
        //poolName  MultithreadEventExecutorGroup
        String poolName = StringUtil.simpleClassName(poolType);
        switch (poolName.length()) {
            case 0:
                return "unknown";
            case 1:
                return poolName.toLowerCase(Locale.US);
            default:
                if (Character.isUpperCase(poolName.charAt(0)) && Character.isLowerCase(poolName.charAt(1))) {
                    return Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1);
                } else {
                    return poolName;
                }
        }
    }

    public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
        if (poolName == null) {
            throw new NullPointerException("poolName");
        }
        if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
            throw new IllegalArgumentException(
                    "priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
        }

        /**
         * 线程name nioEventLoopGroup '-' 第几个eventLoop '-' 当前eventLoop中的第几个线程
         *
         * poolId是一个静态的
         */
        prefix = poolName + '-' + poolId.incrementAndGet() + '-';
        this.daemon = daemon;
        this.priority = priority;
        this.threadGroup = threadGroup;
    }

主要就是thread的prefix的处理

    @Override
    public Thread newThread(Runnable r) {
        Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet());
        try {
            if (t.isDaemon() != daemon) {
                t.setDaemon(daemon);
            }

            if (t.getPriority() != priority) {
                t.setPriority(priority);
            }
        } catch (Exception ignored) {
            // Doesn't matter even if failed to set.
        }
        return t;
    }

    /**
     * @param r
     * @param name  nioEventLoopGroup-2-1
     * @return
     */
    protected Thread newThread(Runnable r, String name) {
        return new FastThreadLocalThread(threadGroup, r, name);
    }

FastThreadLocalThread这是一个继承Thread的类,内部维护了一个map,保存线程局部变量使用

children = new EventExecutor[nThreads]在回头看NioEventLoop的创建newChild(executor, args)
io.netty.channel.nio.NioEventLoopGroup#newChild

    @Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        //this NioEventLoopGroup   executor 线程执行器,每次都会创建一个新的线程
        return new NioEventLoop(this, executor, (SelectorProvider) args[0],
            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
    }

chooser = chooserFactory.newChooser(children)
创建线程选择器

    @Override
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        //判断是否是2的次方
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }

这里又一个优化的地方就是,创建EventExecutorChooser的具体实现类的时候是根据executors的length来决定的,netty为了优化也是够丧心病狂的

    /**
     * 创建线程选择器
     *                          NioEventLoop(work) 新来一个连接 index++
     * NioEventLoop(boss)     0     1     2      3      4
     *                       →
     *
     *                       线程选择器的优化,如果NioEventLoop(work) 线程个数是2的幂  2   4   8  16
     *                       那么返回一个PowerOfTwoEventExecutorChooser  否则  GenericEventExecutorChooser
     *
     *                          index++ & (len-1)                                index++ % (len-1)
     */

PowerOfTwoEventExecutorChooser

    private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            //使用位&操作符来觉得当前任务选用那个NioEventLoop
            //executors就是NioEventLoopGroup中创建的NioEventLoop数组(具体的执行操作者)
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    }

GenericEventExecutorChooser

    private static final class GenericEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        GenericEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            //不是2的次方  那么就取模来决定当前任务选用那个NioEventLoop
            return executors[Math.abs(idx.getAndIncrement() % executors.length)];
        }
    }

再来看NioEventLoopGroup的几个方法
io.netty.util.concurrent.MultithreadEventExecutorGroup#newDefaultThreadFactory

    protected ThreadFactory newDefaultThreadFactory() {
        return new DefaultThreadFactory(getClass());
    }

前面已经说过创建线程的生产工厂,最后返回FastThreadLocalThread


io.netty.util.concurrent.MultithreadEventExecutorGroup#next

    @Override
    public EventExecutor next() {
        return chooser.next();
    }

根据上面对线程选择器的说明,这里会去children NioEventLoop[]中去拿到运算之后的NioEventLoop并返回


下一篇分析NioEventLoop的执行逻辑

猜你喜欢

转载自blog.csdn.net/u011702633/article/details/81945814