实际项目中如何使用线程池
工作后,接触过定义线程池的情况只有全局一个线程池,由前辈设置,自己用就可以了。再就是使用 Springboot 提供的 ,想知道大家一般在生产中的线程池是怎么定义的和使用的
线程池定义在哪里,是全局( xxThreadUtil )还是业务类(xxxService 的 private static)里面
单个线程池执行所有任务好像不太合适,应该不止一个线程池,多个线程池的话是按什么分类和分配线程池参数的呢
在一个项目里定义多个线程池感觉主要是为了线程不会相互依赖,性能上应该不会提升?
执行任务的方式,使用线程池的 submit 、execute ? 或者 CompleteableFeature?
感觉多线程这一块的技术还是非常多内容,无论是思想还是实细节,我常常在想 node 真的好优雅啊,提供简单的 api 就很方便实现异步执行,其他语言里面好像要知道很多细节才可以编写多线程代码
由于本人技术菜单一批,可能有的问题比较蠢,恳请大家不吝赐教
不想打字,你可以选择直接问 gpt ,它比我们大部分人说的明白
以下是来自 chatgpt 的回答1. 线程池定义在哪里?线程池的定义通常应该放在一个全局的工具类(如 ThreadPoolUtil )或者专门的配置类中。这样做有助于集中管理和配置线程池,提高代码的可维护性。在业务类中定义线程池(例如在 xxxService 的 private static )通常不是最佳实践,因为线程池的配置和管理应该是全局的,而不仅仅局限于某个业务类。2. 单个线程池执行所有任务还是多个线程池?是否使用单个线程池还是多个线程池取决于任务的特性和要求。一般来说,使用单个线程池可能会更简单,但在某些情况下,使用多个线程池可能更合适。多个线程池可以根据任务的类型、优先级、执行时间等因素进行分类和分配,以更好地满足不同任务的需求。3. 多个线程池的优势和性能提升?定义多个线程池的主要目的不仅仅是为了避免线程相互依赖,还可以根据任务的性质进行更细粒度的控制。这样可以提高资源的利用率,更好地适应不同类型的任务。性能提升的效果取决于具体的应用场景和任务类型,可能并不总是显著的。在某些情况下,使用多个线程池可能更适合任务的分配和调度。4. 执行任务的方式?在使用线程池执行任务时,可以使用 submit 方法或 execute 方法,具体选择取决于你对任务执行结果的需求。
谨慎用在生产
异步和多线程本来就是两回事以前搞一堆线程,大部分都是因为阻塞 io
node 并发叫优雅?你那叫异步回调,最常用的 debounce 底层还是必须有个有个异步池支持,玩过 rxjs 没?别说 Promise 一把梭╮( ̄▽ ̄"")╭
tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html
按需,慎用,不到万不得已不给系统加这方面的复杂度
V2EX 不允许在回复出现 gpt 回复内容
业务开发就别纠结了,改用什么就用什么。线程池用的最多的是后端框架和客户端请求池,你没看错客户端也用的很多,而且频繁程度很高,http 异步也需要一个线程池管理着。
用啥线程池呢,直接上 jdk21 用虚拟线程
线程池 Spring 配置 bean 用的时候注入 + CompletableFuture
全局,不管 util 类还是 spring bean 管理,都是其中一种实现方式。按需,小组自己评估哪些任务可以丢到哪些池里去,相当于给池定义他的领域,属于他领域的就用他,谁用了池,哪里用了池,要评估,不要一个人随便写个池,别人也随便在随便用你的池。慎用,除非没有其他办法,一般不用池。现在这个时间,一般公司用的都是 future 。Java21 的虚拟线程,现在可以忽略。生产项目都还没几个 Java21 实践。
1.定义在合适的地方,要看具体的需求2.同一类的任务放一个线程池,防止互相干扰,也便于优化3.减少依赖和干扰,优化执行效率肯定提升性能4.肯定看情况使用,CompletableFuture 最强大,不仅获取异步结果,而且可以设置超时和组合java 的多线程已经提供足够好的库已经足够好用了,能够跟 java 多线程比的也就是协程了node 这种半残语言只有一个线程,根本没有多线程。只适合 io 型工作,遇到 cpu 型就是废物。不要提可以多进程 node 也能做 cpu 型工作,不仅麻烦不好维护,也难于优化而 java 的多线程有优秀的框架,使用也比较简单,工程师更多时候花在优化参数上,而且可以胜任复杂的业务场景node 跟 java 比完全没有一战之力
底层类库用的,业务中谨慎使用
- 有坑,自定义线程池做异步任务。2. 统一定义线程池工具类,统一构造器,统一优雅关闭,业务需要线程池使用构造器创建,具体的线程数量根据 io 、cpu 实际情况设定。3. spring 的 scheduled 有坑,默认线程池核心数是 1 ,如果有很多任务,任务同间隔时间执行,会出现任务不执行的问题。解决问题:1. org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration#taskSchedulerBuilder 构建任务调度线程池,org.springframework.boot.autoconfigure.task.TaskSchedulingProperties 查看这个类,根据 ("spring.task.scheduling")在配置文件中修改线程池相关初始化参数。2. 自定义任务调度线程池,使用 org.springframework.scheduling.config.ScheduledTaskRegistrar#setScheduler 注册。
1.视业务而定,如果是一个低频的业务和其它业务共享一个线程池也无伤大雅,如果相对并发较高,最好是指定用自己的线程池而不是公用的线程池,@Async 也是可以指定线程池的,和 private static 的方式基本上是等价的,大多数情况下都可以用它;2.参数没有标准,完完全全根据业务的情况而定,这个情况不仅是当下还有对未来的适当评估;3.线程池主要是用于隔离线程资源和多参数任务并行降低 rt ,其对于整个应用资源的利用率并不会有显著的提升;4. execute 适用于没有返回值的任务,submit 的返回值是 Future ,基本上能用 submit 没啥必要了,CompleteableFuture 本来就是为了加强 Future 的。对于业务中我是建议能不能则不用,作为排名靠后的一个选择,顺便贴一些使用线程池的注意点:- 合适的任务队列及其大小,过大会造成 oom ;- ThreadLocal(登录信息上下文或其它的业务信息)丢失;- 全链路 id 丢失;- 合适的线程池策略和线程数(固定数目和不定数目);- 任务重启丢失(优雅退出);
正确的讲,负责异步的是执行器,不是线程池。线程池只是执行器的组件,在此之外的组件还有任务队列、以及执行器的总控制。另外,不是所有执行器都需要线程池,你要高兴,完全可以用单线程搞个执行器。执行器如何配置参数,直接看各 Excutor 类的 Javadoc 即可,压根不需要求别人。执行器在何时初始化、何时销毁、以及如何获取,这是个问题,但这个问题其实不是执行其的问题,而是如何将执行器放到 JVM 的问题。这个东西 Java 用熟了自然就回了,最简单的就是直接挂 static + 使用 static 代码块。异步执行的原理就是这么复杂,你所谓的优雅,不是优雅,只是隐藏了底层 API ,同时也失去了定制能力的傻瓜式 API 而已。
1.Bean 的方式创建、管理线程池2.不同的业务使用不同的线程池3.CompletableFuture 用起来很方便目前我是这样用 没出过啥问题public class ThreadPoolConfig { (destroyMethod = "shutdown", name = "xxxxxThreadPool") public ThreadPoolExecutor xxxxxThreadPool() { ThreadFactory tf = new ThreadFactoryBuilder().setNameFormat("xxxxxThreadPool-%d").build(); return new ThreadPoolExecutor( Runtime.getRuntime().availableProcessors() , Runtime.getRuntime().availableProcessors() * 2, xxx, TimeUnit.SECONDS, new ArrayBlockingQueue<>(xxxx), tf, new ThreadPoolExecutor.CallerRunsPolicy()); } (destroyMethod = "shutdown", name = "xxxxxThreadPool") public ThreadPoolExecutor xxxxxThreadPool() {}}
注意区分业务场景,举个例子,你就明白了,有 2 个服务,A 调用 B ,B 服务有几次 mysql 超时,A 调用 B 的线程池,因为 B 的超时,全部等待,然后 A---挂了。(事后 B 还嘲讽了 A 的负责人,然后群里吵起来了....) 这个应该算生产比较容易出故障的场景
没有 SLA 就是这样的啦。其实不给 SLA ,A 也有个办法就是坏一个丢一个(池扩张一),反正 B 的问题。
在 BFF 层聚合数据的时候用的多,一般会同时调好几个接口。这边使用上线程池一般都托管给 Spring 。最近在改造成基于 Dag 来编排任务执行了,不过基础还是让线程池执行
spring: threads: virtual: enabled: true
Spring Boot 3.2 打开虚拟线程开关,你都不用管了,直接 注解无脑用了
没有,觉得 await 和 async 关键字挺好的
这篇之前也看过
老项目 java8,我自己项目的话,我就直接 new Thread().start 了 哈哈
嗯嗯,公司的项目我还不敢随便配
哈哈不知道
就是不知道用啥感觉
感谢回答,就是感觉 Node 单线程可以很方便进行异步挺好的,而且我也不知道啥算 CPU 密集型
嗯嗯,可是项目中定义线程池还是蛮普遍的
感谢回答
谢谢回答, 我还有个疑问如果一个项目中定义了多个线程池,例如 2 个线程池,核心线程数都是 5 ,机器 cpu 核数是 5 , 那么可以同时执行 10 个任务吗? 线程池定义多了是不是作用不大了
大佬,我茅厕顿开
确实需要慎用, 目前公司做的 toB 业务,一个大接口响应 10s 都不要优化
谢谢回答,感谢贴出代码, 很有参考意义
感觉 java 已经很先进了, 然而项目还是 java8hah
这么爽的嘛
我们线上业务不复杂但是并发高而且时长要求严格,项目全局用一个公共的线程池,包括 springweb 和 CompleteableFuture 等一些组件的默认线程池都替换了,好处坏处都有,视项目而定
可以看一下 rocketmq 源码里面是如何使用线程池的,全局搜索一下就可以
“At 11:31:30pm UTC on Feb 13, 2009, Unix time will reach 1,234,567,890. Where will you b…
做计算机视觉的,想组一台好一点的工作站,显卡打算买 rtx pro 6000 ,预算 10w 左右。 显卡 6.5 左右,主机 3.5 ,视觉计算,可以考虑一下 9174F…
公司配的 windows 不能升 11 ,自够一台 mini PC 来体验; Apple 七件套配了,生态体验不错,但是想体验多样性; 现在使用发现使用率很低,所以你们的 w…
合速度