面试官:NIOEventLoopGroup源码?
Posted 码农秘籍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官:NIOEventLoopGroup源码?相关的知识,希望对你有一定的参考价值。
JVM 与调优 21 题【已完结】
并发编程 28 题【已完结】
Spring 25 题【已完结】
设计模式 10 题【已完结】
Spring Boot 22 题【已完结】
Netty 10 题【进行中】
面试题解析汇总请点击原文连接查看。
▌题目
▌解析
我们都知道Netty的线程模型是基于React的线程模型,并且我们都知道Netty是一个高性能的NIO框架,那么其线程模型必定是它的重要贡献之一。
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);
... // 已省略非相关代码
// 侦听8000端口
ChannelFuture f = b.bind(8000).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
public NioEventLoopGroup() {
this(0);
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
nThreads:0
executor:null
selectorProvider:SelectorProvider.provider()
selectStrategyFactory:DefaultSelectStrategyFactory.INSTANCE
以及指定了拒绝策略RejectedExecutionHandlers.reject()
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
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);
}
}
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}
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)];
}
}
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
// 为了便于代码剖析,以省略非相关代码
// 初始化executor
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
// 初始化EventExecutor
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
children[i] = newChild(executor, args);
}
// 生成选择器对象
chooser = chooserFactory.newChooser(children);
}
1、初始化executor为ThreadPerTaskExecutor的实例:
通过前面的构造方法调用,我们知道executor为null,所以在此构造方法中,executor会被初始化为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();
}
}
在MultithreadEventExecutorGroup的构造方法中我们看到,EventExecutor数组children初始化时是通过newChild(executor, args)实现的,而newChild的在MultithreadEventExecutorGroup中是个抽象方法
protected abstract EventExecutor newChild(Executor executor, Object... args) throws Exception;
@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]);
}
chooser = chooserFactory.newChooser(children);
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
1、NioEventLoopGroup初始化时未指定线程数,那么会使用默认线程数,
即 线程数 = CPU核心数 * 2;
2、每个NioEventLoopGroup对象内部都有一组可执行的NioEventLoop(NioEventLoop对象内部包含的excutor对象为ThreadPerTaskExecutor类型)
3、每个NioEventLoopGroup对象都有一个NioEventLoop选择器与之对应,其会根据NioEventLoop的个数,动态选择chooser(如果是2的幂次方,则按位运算,否则使用普通的轮询)
朕已阅
以上是关于面试官:NIOEventLoopGroup源码?的主要内容,如果未能解决你的问题,请参考以下文章
Netty中NioEventLoopGroup的创建源码分析
Netty4.XNetty源码分析之NioEventLoopGroup