【Netty4.X】Netty源码分析之NioEventLoopGroup(五)
2017-05-24 17:31
1396 查看
NioEventLoopGroup实际是NioEventLoop的线程组,主要负责管理EventLoop的生命周期,EventLoop的默认大小是2倍的CPU核数,但这并不是一个恒定的最佳数量,为了避免线程上下文切换,只要能满足要求,这个值其实越小越好。
继承关系如下:
首先看NioEventLoopGroup构造方法:
从以上代码可以发现NioEventLoopGroup虽然有4个构造方法,但最终调用的是MultithreadEventLoopGroup的构造方法,代码如下:
在NioEventLoopGroup初始化之前,会先执行父类MultithreadEventLoopGroup的静态模块,其中DEFAULT_EVENT_LOOP_THREADS的大小默认是CPU核数的两倍,就是文章开头说过的。
MultithreadEventExecutorGroup的构造方法:
回到NioEventLoopGroup的newChild方法重载
MultithreadEventExecutorGroup构造方法中执行的是NioEventLoopGroup中的newChild方法,所以children元素的实际类型是NioEventLoop。
解释下EventExecutorChooser的选择
它是根据线程数组大小是否是2的幂次方来选择初始化chooser。如果大小为2的幂次方,则采用PowerOfTwoEventExecutorChooser,否则使用GenericEventExecutorChooser。也就是如果线程数是2的倍数时,Netty选择线程时会使用PowerOfTwoEventExecutorChooser,因为&比%更快(Netty为了性能也是拼了)。
作者:小毛驴,一个游戏人
梦想:世界和平
github主页:https://liulongling.github.io/
csdn主页:http://blog.csdn.net/liulongling
简书主页:http://www.jianshu.com/u/1342f21e1748
若有错误之处,请多多谅解并欢迎批评指正。
本博客中未标明转载的文章归作者小毛驴所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
继承关系如下:
首先看NioEventLoopGroup构造方法:
public NioEventLoopGroup() { this(0); } public NioEventLoopGroup(int nThreads) { this(nThreads, null); } public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) { this(nThreads, threadFactory, SelectorProvider.provider()); } public NioEventLoopGroup( int nThreads, ThreadFactory threadFactory, final SelectorProvider selectorProvider) { super(nThreads, threadFactory, selectorProvider); }
从以上代码可以发现NioEventLoopGroup虽然有4个构造方法,但最终调用的是MultithreadEventLoopGroup的构造方法,代码如下:
protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) { super(nThreads == 0? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args); } private static final int DEFAULT_EVENT_LOOP_THREADS; static { DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt( "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2)); if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS); } }
在NioEventLoopGroup初始化之前,会先执行父类MultithreadEventLoopGroup的静态模块,其中DEFAULT_EVENT_LOOP_THREADS的大小默认是CPU核数的两倍,就是文章开头说过的。
MultithreadEventExecutorGroup的构造方法:
//EventExecutor数组,保存eventLoop private final EventExecutor[] children; //从children中选取一个eventLoop的策略 private final EventExecutorChooser chooser; protected MultithreadEventExecutorGroup(int nThreads, ThreadFactory threadFactory, Object... args) { if (nThreads <= 0) { throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads)); } if (threadFactory == null) { //是一个通用的ThreadFactory实现,方便配置线程池 threadFactory = newDefaultThreadFactory(); } //根据线程数来创建SingleThreadEventExecutor数组 //从命名上可以看出SingleThreadEventExecutor是一个只有一个线程的线程池 children = new SingleThreadEventExecutor[nThreads]; //根据children数组的大小,采用不同策略初始化chooser。 if (isPowerOfTwo(children.length)) { chooser = new PowerOfTwoEventExecutorChooser(); } else { chooser = new GenericEventExecutorChooser(); } for (int i = 0; i < nThreads; i ++) { boolean success = false; try { // children[i] = newChild(threadFactory, 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 { //如果没有创建成功,循环关闭所有SingleThreadEventExecutor 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) { Thread.currentThread().interrupt(); break; } } } } } 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); } }
回到NioEventLoopGroup的newChild方法重载
@Override protected EventExecutor newChild( ThreadFactory threadFactory, Object... args) throws Exception { return new NioEventLoop(this, threadFactory, (SelectorProvider) args[0]); }
MultithreadEventExecutorGroup构造方法中执行的是NioEventLoopGroup中的newChild方法,所以children元素的实际类型是NioEventLoop。
解释下EventExecutorChooser的选择
//判断一个数是否是2的幂次方 private static boolean isPowerOfTwo(int val) { return (val & -val) == val; } private final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser { @Override public EventExecutor next() { return children[childIndex.getAndIncrement() & children.length - 1]; } } private final class GenericEventExecutorChooser implements EventExecutorChooser { @Override public EventExecutor next() { return children[Math.abs(childIndex.getAndIncrement() % children.length)]; } }
它是根据线程数组大小是否是2的幂次方来选择初始化chooser。如果大小为2的幂次方,则采用PowerOfTwoEventExecutorChooser,否则使用GenericEventExecutorChooser。也就是如果线程数是2的倍数时,Netty选择线程时会使用PowerOfTwoEventExecutorChooser,因为&比%更快(Netty为了性能也是拼了)。
作者:小毛驴,一个游戏人
梦想:世界和平
github主页:https://liulongling.github.io/
csdn主页:http://blog.csdn.net/liulongling
简书主页:http://www.jianshu.com/u/1342f21e1748
若有错误之处,请多多谅解并欢迎批评指正。
本博客中未标明转载的文章归作者小毛驴所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章推荐
- Netty线程模型源码分析之NioEventLoopGroup的初始化
- 【Netty4.X】Netty源码分析之NioEventLoop(六)
- Netty源码分析:NioEventLoopGroup
- Netty源码学习——EventLoopGroup原理:NioEventLoopGroup分析
- Netty学习之旅------再谈线程模型之源码分析NioEventLoopGroup、SingleThreadEventExecutor
- Netty源码分析:NioEventLoop启动以及其IO操作和Task任务的处理
- netty4源码分析——NioEventLoop
- netty 启动分析 NioEventLoopGroup
- netty源码分析(一)EventLoopGroup
- Netty源码分析之NioEventLoop(转)
- Netty源码学习(二)NioEventLoopGroup
- Netty 4.0源码分析1:服务端启动过程中的Channel与EventLoopGroup的注册
- 【Netty源码解析】NioEventLoop
- Netty4学习笔记-- NioEventLoopGroup NioEventLoop
- netty NioEventLoopGroup 线程名称设置
- Netty源码分析系列1——NIOEventLoopGroup的创建
- 【Netty源码学习】EventLoopGroup
- netty源码学习二(EventLoopGroup、EventLoop)
- 【Netty源码学习】EventLoopGroup