向南是个万人迷

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

Netty源码分析第二章:NioEventLoop

 

第三节:初始化线程选择器

到上一小节的MultithreadEventExecutorGroup类的构造方法:

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, 
                                        EventExecutorChooserFactory chooserFactory, Object... args) {
    //代码省略
    if (executor == null) {
        //创建一个新的线程执行器(1)
        executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
    }
    //构造NioEventLoop(2)
    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) {
            throw new IllegalStateException("failed to create a child event loop", e);
        } finally {
           //代码省略
        }
    }
    //创建线程选择器(3)
    chooser = chooserFactory.newChooser(children);
    //代码省略
}

我们看第三步, 创建线程选择器:

chooser = chooserFactory.newChooser(children);

NioEventLoop都绑定一个chooser对象, 作为线程选择器, 通过这个线程选择器, 为每一个channel分配不同的线程

我们看到newChooser(children)传入了NioEventLoop数组

我们跟到DefaultEventExecutorChooserFactory类中的newChooser方法:

public EventExecutorChooser newChooser(EventExecutor[] executors) { 
    if (isPowerOfTwo(executors.length)) { 
        return new PowerOfTowEventExecutorChooser(executors);
    } else {
        return new GenericEventExecutorChooser(executors);
    }
}

这里通过 isPowerOfTwo(executors.length) 判断NioEventLoop的线程数是不是2的倍数, 然后根据判断结果返回两种选择器对象, 这里使用到java设计模式的策略模式

根据这两个类的名字不难看出, 如果是2的倍数, 使用的是一种高性能的方式选择线程, 如果不是2的倍数, 则使用一种比较普通的线程选择方式

我们简单跟进这两种策略的选择器对象中看一下, 首先看一下PowerOfTowEventExecutorChooser这个类:

private static final class PowerOfTowEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;
    PowerOfTowEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }
    @Override
    public EventExecutor next() {
        return executors[idx.getAndIncrement() & executors.length - 1];
    }
}

这个类实现了线程选择器的接口EventExecutorChooser, 构造方法中初始化了NioEventLoop线程数组

重点关注下next()方法, next()方法就是选择下一个线程的方法, 如果线程数是2的倍数, 这里通过按位与进行计算, 所以效率极高

再看一下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() {
        return executors[Math.abs(idx.getAndIncrement() % executors.length)];
    }
}

这个类同样实现了线程选择器的接口EventExecutorChooser, 并在造方法中初始化了NioEventLoop线程数组

再看这个类的next()方法, 如果线程数不是2的倍数, 则用绝对值和取模的这种效率一般的方式进行线程选择

 

这样, 我们就初始化了线程选择器对象

 

上一节: NioEventLoopGroup之NioEventLoop的创建

下一节: NioEventLoop线程启动

 

posted on 2018-12-31 18:50  向南是个万人迷  阅读(912)  评论(0编辑  收藏  举报