Netty学习笔记(四)NioEventLoopGroup分析

引子

在上一篇文章中我们已经分析了Netty注册相关的逻辑,接下来再开看下NioEventLoopGroup这个类内部的相关构造。

NioEventLoopGroup

在之前的demo中第一行就是:

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

这个NioEventLoopGroup类的构造函数最终实现如下:

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        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;
                ......
                }
        }
    }

其中传入的参数Executor对象就是多线程中的线程池接口的实现类(关于这块内容我特定又回过头去看多线程相关的知识,具体可以看另外一篇关于java多线程的文章)。接着来看一开始这个线程池对象是空的,就开始创建ThreadPerTaskExecutor实例,
我们首先就从这个ThreadPerTaskExecutor对象开始分析。

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;
    }

    @Override
    public void execute(Runnable command) {
        threadFactory.newThread(command).start();
    }
}

从代码就可以看出ThreadPerTaskExecutor就是一个一个实现了Executor线程池的实现类,
execute方法内部开始调用线程工厂的newThread方法创建线程。当后续执行线程工厂的execute方法时就会创建一个新的线程。
传入的参数是一个newDefaultThreadFactory实例,这个对象实现了ThreadFactory工厂接口,所以就是一个线程工厂类,它的构造函数实现如下:

    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 ......
        }
        prefix = poolName + '-' + poolId.incrementAndGet() + '-';
        this.daemon = daemon;
        this.priority = priority;
        this.threadGroup = threadGroup;
    }

看到这我们先对上面的内容做个小结:

  • 从这两段代码可以看出ThreadPerTaskExecutor()这个方法做的就是创建一个线程池,并且线程池的优先级为Thread.NORM_PRIORITY,即5(优先级越大越优先执行,5是普通的优先级)。
  • 每当new一个NioEventLoopGroup对象的时候,实际上内部就会先创建一个线程池。

newChild()方法分析

上面讲到executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());方法创建了一个线程池。接下来就执行了:

        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                children[i] = newChild(executor, args);
                success = true;
            ......

这个newChild方法实现如下:

    @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]);
    }

    NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
        super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
        if (selectorProvider == null) {
            throw new NullPointerException("selectorProvider");
        }
        if (strategy == null) {
            throw new NullPointerException("selectStrategy");
        }
        provider = selectorProvider;
        selector = openSelector();
        selectStrategy = strategy;
    }

从源码中可以看出newChild方法创建了一个NioEventLoop对象。构造方法中除了给变量赋值外,又调了父类的构造方法,继续往下看:

    protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
                                        boolean addTaskWakesUp, int maxPendingTasks,
                                        RejectedExecutionHandler rejectedHandler) {
        super(parent);
        this.addTaskWakesUp = addTaskWakesUp;
        this.maxPendingTasks = Math.max(16, maxPendingTasks);
        this.executor = ObjectUtil.checkNotNull(executor, "executor");
        taskQueue = newTaskQueue(this.maxPendingTasks);
        rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
    }

从这两部分看出newChild方法主要是创建了一个NioEventLoop对象,这个对象内部保存了provider,selector,selectStrategy以及一个taskQueue队列。这里的provider就是Java NIO中的选择器provider,selector就是选择器,至于这些东西具体是怎么用的,这里我还是疑惑的,要后面用到的地方继续分析了。

newChooser

接下来看NioEventLoopGroup构造函数的第三部分:

        chooser = chooserFactory.newChooser(children);

这里传入的children数组就是上面讲到的创建的NioEventLoop数组,但是返回的这个chooser是个什么鬼,又不懂了,真是头疼~。所以这里先保留这个疑问吧,只能后续学习明白了再回头补了。

你可能感兴趣的:(Netty学习笔记(四)NioEventLoopGroup分析)