NioEventLoopGroup源码解读

NioEventLoopGroup其实就是reactor模式中的reactor的角色,本节我们先来看看NioEventLoopGroup在new的过程当中做了哪些事情

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

使用new创建NioEventLoopGroup时,会经过一系列构造方法调用,最终调用到上图中5个参数的构造方法,该构造方法会调用到父类MultithreadEventLoopGroup的构造方法,其中线程数如果不传,默认为cpu个数乘以2,源码如下

protected MultithreadEventExecutorGroup(int nThreads, 
                                        Executor executor,
                                        EventExecutorChooserFactory chooserFactory, 
                                        Object... args) {
    if (nThreads <= 0) {
        throw new IllegalArgumentException(String.format(
            "nThreads: %d (expected: > 0)", nThreads));
    }
    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;
                    }
                }
            }
        }
    }
    chooser = chooserFactory.newChooser(children);
    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);
    }
    Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);
}

上面代码中,会先生成一个执行器executor,ThreadPerTaskExecutor的构造函数接收一个DefaultThreadFactory类型的对象做为参数赋值给自己的成员变量threadFactory,该类中还有一个execute方法用来通过threadFactory对象生成一个线程对象并启动该线程,DefaultThreadFactory类实现了ThreadFactory接口,接口中只有一个newThread方法用来创建Thread对象

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();
    }
}
public class DefaultThreadFactory implements ThreadFactory {
    ......
    public DefaultThreadFactory(Class<?> poolType) {
        this(poolType, false, Thread.NORM_PRIORITY);
    }
    ......省去部分代发
}

接着生成了一个EventExecutor类型的数组children,其实该数组中存储的就是NioEventLoop对象

然后在for循环中做的最主要的事情就是根据线程个数,初始化children数组对象,而该对象的创建是在NioEventLoopGroup中,在newChild方法中通过new NioEventLoop完成对象的创建,NioEventLoop的构造方法如下:

public final class NioEventLoop extends SingleThreadEventLoop {
    ......
    private Selector selector;//java nio中的选择器(多路复用器)
    private Selector unwrappedSelector;
    private SelectedSelectionKeySet selectedKeys;//选择键
    private final SelectorProvider provider;//通过该类生成多路复用器Selector
    
    ......
    //io线程和用户线程所占的比例
    private volatile int ioRatio = 50;
    ......
    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;
       final SelectorTuple selectorTuple = openSelector();
       selector = selectorTuple.selector;
       unwrappedSelector = selectorTuple.unwrappedSelector;
       selectStrategy = strategy;
    }
}

通过源码可以看到NioEventLoop中设置了Selector和selectedKeys,学过java nio的都知道这是jdk的类,因为netty也是包装nio实现的框架,而nio又是Reactor模式的实现,Reactor模式后续单独讲,本章节只讲NioEventLoopGroup在创建时所做的事情,构造函数中,首先调用的父类SingleThreadEventLoop的构造函数,接着进行一下赋值操作,其中最重要的就是生成多路复用器Selector,通过调用openSelector()实现,如下

private SelectorTuple openSelector() {
    final Selector unwrappedSelector;
    try {
        unwrappedSelector = provider.openSelector();
    } catch (IOException e) {
        throw new ChannelException("failed to open a new selector", e);
    }
    ......
}

MultithreadEventExecutorGroup中有如下一个成员属性,其中通过GlobalEventExecutor.INSTANCE的创建,完成了延迟队列

private final Promise<?> terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);

private GlobalEventExecutor() {
    //完成延迟队列的初始化
    scheduledTaskQueue().add(quietPeriodTask);
    threadFactory = ThreadExecutorMap.apply(new DefaultThreadFactory(
        DefaultThreadFactory.toPoolName(getClass()), false, Thread.NORM_PRIORITY, null), this);
}

父类SingleThreadEventLoop的构造函数中友调用了自己的父类SingleThreadEventExecutor的构造函数,SingleThreadEventLoop完成了对tailTasks队列的初始化

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
    ......
	private final Queue<Runnable> tailTasks;
    ......
    protected SingleThreadEventLoop(EventLoopGroup parent, 
                                    Executor executor,
                                    boolean addTaskWakesUp, 
                                    int maxPendingTasks,
                                    RejectedExecutionHandler rejectedExecutionHandler) {
        super(parent, executor, addTaskWakesUp, maxPendingTasks,rejectedExecutionHandler);
        tailTasks = newTaskQueue(maxPendingTasks);
    }
  	......
    /**
    * Create a new {@link Queue} which will holds the tasks to execute. This default implementation will return a
    * {@link LinkedBlockingQueue} but if your sub-class of {@link SingleThreadEventExecutor} will not do any blocking
    * calls on the this {@link Queue} it may make sense to {@code @Override} this and return some more performant
    * implementation that does not support blocking operations at all.
    */
    protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
        return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
    }
   	.......
}

SingleThreadEventExecutor中的构造函数中,先调用了父类AbstractScheduledEventExecutor的构造函数,接着又调用了AbstractEventExecutor的构造函数,接着SingleThreadEventExecutor的构造函数中进行一些赋值操作,并创建了一个链表的阻塞队列taskQueue,该队列用于存储需要执行的任务

public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
    ......
    private final Queue<Runnable> taskQueue;
    ......
    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 = ThreadExecutorMap.apply(executor, this);
        taskQueue = newTaskQueue(this.maxPendingTasks);
   		rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler,
                                                      "rejectedHandler");
    }
    ......
    protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
        return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
    }
}

上面由new NioEventLoop()对应的一系列构造方法操作完成后,第37行代码创建了一个EventExecutorChooserFactory.EventExecutorChooser的chooser对象,代码如下

public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
    ......省略部分代码
    @Override
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }
    //判断是不是2的n次方
    private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;
    }
    
    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() {
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    }

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

进入newChooser方法中,先通过isPowerOfTwo方法判断executors数组长度是不是2的n次方,这里需要注意的是(val & -val) == val,这种写法就是经典的2的n次方的判断方式,接着对不同条件有两种实现方式,而PowerOfTwoEventExecutorChooser和GenericEventExecutorChooser都持有了EventExecutor数组对象,并通过next从EventExecutor数组中取得NioEventLoop对象,所以其他类中要想从数组中获取NioEventLoop对象,都需要通过chooser对象都next方法获取

总结:

当我们创建NioEventLoopGroup对象都时候,主要做了如下几件事情

  • 完成了线程池的初始化,并放到了EventExecutor类型的children数组对象中,该数组中的NioEventLoop对象通过chooser对象根据不同的算法获取
  • 创建了Selector对象,并于NioEventLoop进行关联(是NioEventLoop的成员变量)
  • 创建了两个阻塞队列tailTasks和taskQueue,其中taskQueue就是NioEventLoop执行任务所使用的队列
  • 创建了EventExecutorChooserFactory.EventExecutorChooser类型的chooser对象,通过该对象的next方法从EventExecutor数组中获取
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值