java中的executor是什么 线程池Executor的4种创建方式

这就是陷阱:直接使用 Executors.newXXX 创建线程池可能会导致 OOM。

推荐实践:使用ThreadPoolExecutor配置线程池,控制主线程数、最大线程数、队列类型、拒绝策略。

实用提醒:避免使用无界队列并正确设置KeepAliveTime。

线程池的四种创建方式及区别

你的问题让我有点困惑。
我在线程池方面遇到了很多缺点,但是我从来没有直接遇到过你描述的参数组合。
但没关系。
我们来一一谈谈,看看你觉得合不合适。

比如你提到的newFixedThreadPool,核心线程数为0,非核心线程数为MAX_VALUE。
队列没有值,并且队列始终被认为已满,因此每当任务到达时就会创建非核心线程。
这看起来相当极端。
当时我尝试在项目中做类似的事情,系统卡住了,因为线程一直在创建,内存已满。
那是2 01 9 年,用的是Java 8 后来改成了固定核数,队列中使用了LinkedBlockingQueue,解决了很多问题。

另一个例子是newSingleThreadPool。
核心线程数为1 ,非核心线程数为1 ,队列无限制。
我很熟悉它。
许多小工具使用它来确保单线程顺序执行。
但你必须小心无限的队列。
有一次,我有一项任务需要很长时间才能完成。
结果队列里堆积的任务越来越多,最后直接导致了outofmemory错误。
这是一个移动项目,设备的内存很小,实际上有生命危险。

newScheduledThreadPool 更加复杂,支持计划任务和周期性任务。
核心线程数作为参数传递,非核心线程数为MAX_VALUE,队列为DelayedWorkQueue。
是。
我曾经用它定期清理缓存,并将核心线程数设置为2 结果,有时任务太多,形成一堆非核心线程,系统负载增加。
它处于后台服务中。
监控显示 CPU 峰值超过 9 0%,客户打电话询问发生了什么情况。

就拒绝策略而言,你提到的abort策略是默认的,直接抛出异常。
我曾经遇到过一种情况,大量任务提交,直接抛出RejectedExecutionException,导致程序崩溃。
后来我改用CallerRunsPolicy,将任务交给调用线程执行。
这样,虽然主线程会卡住,但至少程序不会崩溃。
它是在一个网络服务中,用户提交了很多任务。
换了之后我感觉好多了。

一般情况下,线程池要根据实际情况来确定。
如果参数设置不正确,最好的情况下性能会下降,最坏的情况下程序会崩溃。
我建议你先在一个小项目上尝试一下你提到的参数组合,看看真实的效果。
从一开始就不要将它们用于主要业务。
如果你还是不明白,欢迎来问我。
也许你可以避免我当时踏入的陷阱。

java创建线程池有哪几种方式? 为何搜索到的都是说4种

哇,你的总结太全面了,我感觉你把我之前踩过的坑都解决了。
事实上,Java中创建线程池的方法不止这几种。
当你说出这句话时,你才知道,骗局有很多。

上次我在项目中使用执行器的newFixedThreadPool时,由于任务太多而导致内存爆炸。
当时真的很迷茫,没有意识到无休止排队的危害。
后来改成了ThreadPoolExecutor,并定义了ArrayBlockingQueue,问题就解决了。

但是说实话,直接用ThreadPoolExecutor写确实很烦人,要一一指定参数。
但想一想,至少你知道什么是队列,什么是拒绝策略,并且可以安全地使用它。
和newCachedThreadPool一样,我在阿里的手册上看到要谨慎使用。
如果线程数能达到Integer.MAX_VALUE,那不是就等着耗尽了吗? Hutool的ThreadUtil确实很方便。
我上次使用它是为了快速开发。
配置很简单,几分钟即可完成。
但如果你的项目要求较高或者想要细粒度的控制,你还是需要新建自己的ThreadPoolExecutor。

我已经多次使用 ForkJoinPool,它在执行分而治之任务时特别有用。
CPU占用率大大提高,比普通线程池好很多。
不过,似乎使用它的人并不多。
很多框架仍然默认使用CompletableFuture,我认为这已经足够了。

最终,您选择的方法取决于场景。
如果你需要临时做一些小任务,执行者也可以做。
但在真实的生产环境中,你还是要自己新建ThreadPoolExecutor,或者使用Hutool这样的外部工具,这样至少可以避免很多隐藏的风险。
想一想,如果队列变成无穷大,拒绝策略写得不好,万一坏了你会打电话给谁?无论如何,我将在未来的项目中手动编写 ThreadPoolExecutor。
虽然有点烦人,但是很安全。

我还使用了 Spring 的 ThreadPoolTask​​Executor 。
集成非常方便。
可以执行XML配置或注释。
但如果你不是在spring环境下,这个可能就没用了。

所以,你的总结是完全准确的。
基础玩家使用executor,高级玩家则直接编写ThreadPoolExecutor。
至于需求特别是寻找 ForkJoinPool 或 Spring 工具。
反正就看你自己了,每种都有自己的风险和适用场景。