实际项目中如何使用线程池
工作后,接触过定义线程池的情况只有全局一个线程池,由前辈设置,自己用就可以了。再就是使用 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 源码里面是如何使用线程池的,全局搜索一下就可以
目前大四,主要找 Java 后端工作,感觉自己天天背八股,都快背闷了,感觉很无趣看不到正反馈,已经坚持不下去了。还有就是我的基础其实不是很好,就是 CS 那方面的东西。现在这个…
1.最难受的就是圆角设计,真是东施效颦,不知道后续微软会不会把自家 LOGO 也改成圆角的,目前最大的愿望就是希望正式版有改回直角的选项; 2.任务栏的开始图标,一抹浓厚的山寨…
最近在学 react ,自己有 jet brain 全家桶就在用 web storm ,刚才前端同事就问为什么不用 vscode ,轻量化,更快。突然就想到“轻量化”,这个词好…