netty 并发 随笔 1-netty线程模型
创始人
2024-06-02 04:13:09

0. 我们的故事不能忘,太多的情节要发展 ~

从 netty-example 入手真的很不戳,学到了

(其实写这个的东西的动力,有一份部分是想增进一下markdown书写规则的了解)


这里放一段org.netty.example.EchoServer的代码(客户端也大同小异),
本文会基于这个用例代码着手源码走读

// Configure the server.
// EventLoopGroup 即集成了Channel(IO)能力的EventExecutorGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// nThread=0会取一个默认值(与机器的可用处理器相关)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {ServerBootstrap b = new ServerBootstrap();// volatile EventLoopGroup group// volatile EventLoopGroup childGroup// 构建的过程基本没有什么逻辑转换在里面,可以说只是赋值而已b.group(bossGroup, workerGroup)// 这里的channel.class包装到ReflectiveChannelFactory的内部属性中// 当需要使用到时,借助该工厂创建出ServerSocketChannel// ServerBootstrap.channelFactory = channelFactory.channel(NioServerSocketChannel.class)// Map, Object> options做了put.option(ChannelOption.SO_BACKLOG, 100)// volatile ChannelHandler handler// 入参类型:ChannelHandler handler.handler(new LoggingHandler(LogLevel.INFO))// volatile ChannelHandler childHandler// 类型也是:ChannelHandler childHandler.childHandler(new ChannelInitializer() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {// 这个channel绑定了pipeline// pipeline又由多个handler组成ChannelPipeline p = ch.pipeline();p.addLast(new LoggingHandler(LogLevel.INFO));p.addLast(new EchoServerHandler());}});// 前面包装到 ReflectChannelFactory 在这里 doBind() 时初始化channel实例// bind() -> io.netty.bootstrap.AbstractBootstrap.initAndRegister -> 返回 ChannelFuture(channel产出)//  init:工厂创建channel,初始化channel的childHandler的pipeline,赋值option到channel//  register:将channel注册到parentGroup// sync() -> io.netty.util.concurrent.DefaultPromise.await() -> synchronized && waiters ++ChannelFuture f = b.bind(EchoConstants.PORT_SERVER).sync();// Wait until the server socket is closed.f.channel().closeFuture().sync();
} finally {// Shut down all event loops to terminate all threads.bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();
}
  • 至少,通过上面这个服务端代码可以大概地知道相关类有哪些。

  • 建议将其中重要的类做个UML,因为netty是基于juc的线程模型+nio上封装而成,注定会引入一段作者的封装逻辑。

  • 客户端的逻辑基本大同小异

1. 搞清楚相关类是怎么设计的

先来段免责声明:

编者默认读者了解jdk.juc的ExecutorThreadThreadFactory等概念

编者默认读者了解jdk.nio的BufferChannelSelector等概念

编者默认读者了解jdk.net的SocketConnect等概念

1.1 先放大看个局比较简单的设计

请添加图片描述


通过翻阅他们api中出、入参类型的变化,再加上命名上的暗示,可以确定:

  • 相比 juc.future,netty.future新增了 同步执行(await()、sync()都是synchronized(this),sync()多了rethrow)、监听器集成 的能力
  • 相比 netty.future,netty.Promise暴露了 try/set 成功、失败状态 的接口
  • 相比 netty.future,netty.ChannelFuture将很多相同的接口出、入参类型换了 ChannelFuture,埋下了nio的种子
  • 相比 以上两者,netty.ChannelPromise并没有整出啥新活儿,但他是集大成者

1.2 再缩小来看集成整体的设计

请添加图片描述


值得注意的是:

  • netty接入juc的设计:XxxExecutorGroup同时集成了juc.ExecutorService + Iterator(赋值了Group 群组维护的能力)
  • netty接入nio的设计:XxxLoopGroup(图中蓝块) extends XxxExecutorGroup(图中红块),这俩命名接近的Group的区别:引入了ChannelPromise(nio)相关的API
  • netty的内部逻辑设计: Xxx(SingleThread) extends XxxGroup(MultiThread),这意味这俩者还存在着职责/角色的差异

仅仅是了解这几个比较重要的类,还是不能做到通读源码的,我们还可以再补一课:
搞清楚NioEventLoopGroup的全参构造中的入参是干嘛的,以及他们的默认值
这有助我们从入口就开始跟着源码,跟紧源码。

2. 构造NioEventLoopGroup

搞清楚默认值,以及其接口方法是做什么的就行了

下面每个变量使用三行注释来解释:

  • 名称
  • 默认值
  • 去处(主要用途)
public NioEventLoopGroup(// 任务线程数// 默认与当前机器的核心数相关 io.netty.channel.MultithreadEventLoopGroup.DEFAULT_EVENT_LOOP_THREADS// 用于构造 io.netty.util.concurrent.MultithreadEventExecutorGroup.children:EventExecutor[nThreads]int nThreads,// 线程池的实现类// 默认new ThreadPerTaskExecutor(newDefaultThreadFactory())// 也是用于构造 io.netty.util.concurrent.MultithreadEventExecutorGroup.children[i] = newChild(executor, args)Executor executor,// 任务线程的选择策略的工厂// 默认DefaultEventExecutorChooserFactory// EventExecutorChooserFactory chooserFactory,// 用于返回1个轮询连接状态的provider// 默认jdk的工厂(sun.nio.ch.DefaultSelectorProvider)// final SelectorProvider selectorProvider// 轮询连接状态的工厂// 默认io.netty.channel.DefaultSelectStrategyFactory// final SelectStrategyFactory selectStrategyFactory,// 任务拒绝时的处理器// 默认抛异常(io.netty.util.concurrent.RejectedExecutionHandlers.REJECT)// final RejectedExecutionHandler rejectedExecutionHandler,// 任务阻塞队列的工厂// 默认null// 这个先过吧,我也没有注意过这个...final EventLoopTaskQueueFactory taskQueueFactory) {super(nThreads, executor, chooserFactory, selectorProvider, selectStrategyFactory,rejectedExecutionHandler, taskQueueFactory);}

NioEventLoopGroup构造完成后的 ServerBootstrap初始化、构建过程(just赋值,没有啥逻辑的),直接步进到ServerBootstrap.bind()
我错了,有逻辑

顺着NioEventLoopGroup(nThreads)往里狠狠的步进,掠过中间的无逻辑的地方

	// io.netty.util.concurrent.MultithreadEventExecutorGroup#MultithreadEventExecutorGroup(int, java.util.concurrent.Executor, io.netty.util.concurrent.EventExecutorChooserFactory, java.lang.Object...)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) {// 这里赋值默认的线程池(eventLoop的)// 也就是说group下所有的eventLoop的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 typethrow 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 terminationListener = new FutureListener() {@Overridepublic void operationComplete(Future future) throws Exception {if (terminatedChildren.incrementAndGet() == children.length) {terminationFuture.setSuccess(null);}}};for (EventExecutor e: children) {e.terminationFuture().addListener(terminationListener);}Set childrenSet = new LinkedHashSet(children.length);Collections.addAll(childrenSet, children);readonlyChildren = Collections.unmodifiableSet(childrenSet);} 

想了想,还是分成多篇文章吧

上一篇:canvas入门

下一篇:skywalking部署安装

相关内容

热门资讯

苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...