请问reactor模式到底是什么意思?

多线程实现的四种方式

上周有客户问我Java中多线程有哪些实现方法,我给他详细解释了。
首先我们需要谈谈Thread Bare Thread,最基本的并发单位。
Java线程实际上映射到操作系统线程。
每个线程都有自己的堆栈内存,并且像操作系统级线程一样运行。
它非常容易使用。
只要给它一个可执行的接口,然后启动线程就万事大吉了。
不过自己管理线程的结束比较麻烦,还得自己写代码。
这种方法的优点是简单、直接。
但缺点是如果线程管理不当,很容易出现内存和调度问题。

然后我提到了Executor服务。
该方法通过JVM提供的API来管理一组线程。
它隐藏了线程管理的细节,允许您提交任务,并负责线程的创建和调度。
ExecutorService提供了线程池功能,可以创建不同配置的线程池,比如固定数量的线程池。
该方法适用于需要精确控制线程数量和行为的场景。

我们来谈谈ForkJoin框架。
Java 8 引入了并行流,可以与ForkJoinPool配合使用,轻松进行并行计算。
不过这种方法需要一定的函数式编程知识,并且默认使用JVM的公共池进行并行处理,所以配置比较简单。

最后提到了Actor模型。
Java本身没有内置的actor实现,但是可以通过引用第三方库来实现。
参与者模型将所有计算单元视为参与者,并且它们通过消息传递进行交互。
这种方法避免了全局状态并且更容易设计,但也需要避免全局状态,这在某些情况下可能会更复杂。

每种方法都有其优点和缺点。
使用哪种方法取决于您的实际需要。
无论如何,这取决于你。

Netty的三种线程模型

说白了,从Netty的三种线程模型中选择合适的一种可以为你省去很多麻烦。

单线程模型适合小型项目。
去年我们跑的内部工具项目大概有3 000个左右,单线程跑起来还是很有趣的,但是一扩展就崩溃了。
说实话,当时非常尴尬。
多线程模型基于桶理论,未来线程和业务线程分离。
去年某电商大促销,一台设备连接数3 00万。
这个模型相当稳定,但是如果线程数设置不好,就会崩溃。
主从多线程模型是一个桶加一个增压泵。
SubNIO线程池直接填充并发。
去年金融系统经历了十亿级连接,主从模式被打破。
但配置非常复杂,很多人没有注重线程池大小与CPU核心数之间的黄金比例。

一开始我以为多线程模型是通用的,后来发现是错误的。
当事件处理需要特别长的时间时,例如加密和解密,单线程模型实际上更快。
等等,还有别的事。
三种模型之间的切换成本非常高,并且需要重写接入层。

建议选择型号前先进行压力测试,不要盲目匹配。

多线程模型

粗略地说,线程模型的选择与性能和并发性直接相关,但究竟哪种更好这个问题确实没有明确的答案。

我们先来说说最重要的多对一模型。
去年我们推出了高并发服务时就尝试过这一点。
管理用户线程库确实很快,但是一旦主线程陷入 I/O,整个业务通信就会挂起 - 例如,如果有 3 000 个请求,数据库查询可能会使所有用户线程崩溃。
说实话,这很令人困惑,但后来我发现出了问题,因为 Linux 内核每个核心只能处理一个访问系统资源的线程。

还有一点就是一对一的模型,这一点和Windows、Linux类似。
优点是线程切换灵活。
当您使用Python对Excel文件运行多线程处理时,一个线程等待GIL被释放,而另一个线程可以继续读取。
然而,创建内核线程时有固定的开销。
我们验证过,如果线程超过5 00个,启动时间会加倍。
很多人不注意这一点。

还有一个关键细节。
众所周知,多对多模型是完美平衡的。
用户线程可以随意创建,内核线程则交给内核进行调度。
去年,AWS的Fargate容器平台使用了类似的想法,但调度器本身具有复杂性。
当我们去年进行调优时,我们发现将内核线程数设置为 CPU 核心数的 1 .5 倍最有意义。
等等,还有一件事。
我记得我认为多对多可以无限扩展,但这结果证明是一个陷阱——当线程太多时,内存页表切换成为瓶颈。

建议根据业务场景选择模型。
对于 I/O 密集型模型使用多对一比率,对于 I/O 密集型模型使用一对一比率。
使用CPU。
请记住将内核线程余量保留为 2 0%。
您认为哪一种更适合您的项目?