【并发编程六:Java中的线程池(3)-线程池的应用】 ╰半夏微凉° 2023-10-09 14:09 11阅读 0赞 【衔接上一章 [【并发编程五:Java中的线程池(2)-线程的实现原理】][Java_2_-]】 #### 学习路线 #### * * 1.9工作中线程池的应用 * * 1、局部 & 全局单例; * 2、多个业务线程池; * 1.10如何合理设置线程池大小? * * 1、《Java Concurrency in Practice》即《Java并发编程实践》,书中第八章8.2节指出: * 2、《Programming Concurrency on the JVM》即《Java虚拟机并发编程》,书中第二章2.1节指出: * 国内采用的一些方案: * 这些公式可以吗? * 2核cpu示例: * 1.11动态线程池 * * Spring Cloud Alibaba版本说明 * Nacos运行环境部署 ### 1.9工作中线程池的应用 ### #### 1、局部 & 全局单例; #### #### 2、多个业务线程池; #### 根据要执行的任务的特点,使用多个线程池,把相同类型的任务放到同一个线程池中,可以起到隔离的作用,避免一个线程池中的线程阻塞或占满时影响到其它线程池执行; 因为不同业务的特征不一样,有的业务是CPU密集型的,有的业务是IO密集型的,有的任务执行耗时比较长,有的任务执行耗时比较短,有的任务可能是连数据库,有的任务可能是调第三方接口等等,分开使用不同的线程池。 ### 1.10如何合理设置线程池大小? ### 线程池大小设置主要来自于国外的两本书: #### 1、《Java Concurrency in Practice》即《Java并发编程实践》,书中第八章8.2节指出: #### 公式: 其中: Ncpu = cpu的核心数 ,Ucpu = cpu的使用率(在0~1之间) W = 线程等待时间,C = 线程计算时间 8 \* 100% \* (1+60/40) = 20 8 \* 100% \* (1+80/20) = 40 #### 2、《Programming Concurrency on the JVM》即《Java虚拟机并发编程》,书中第二章2.1节指出: #### 公式: 线程数 = CPU可用核心数 / (1 - 阻塞系数) 其中阻塞系数 = 阻塞时间 /(阻塞时间+计算时间),取值为0 - 1 之间; 计算密集型任务的阻塞系数为0,IO密集型任务的阻塞系数接近1,但阻塞系数不可能是1,是1的话表示完全阻塞,这是不存在的; 如果阻塞系数是0.6,就表示有60%的时间在阻塞,有40%的时间在执行任务; 8 / (1-0.6) = 20 8 / (1-0.8) = 40 得到的规律:线程在执行的时候,如果等待时间/阻塞时间比较多,那么就应该设置更多的线程数; 如果等待时间/阻塞时间比较少,那么就应该设置更少的线程数; #### 国内采用的一些方案: #### **- 1、CPU密集型**: 任务需要大量使用CPU进行运算,但是没有阻塞,CPU一直高速运行; 该情况下应尽可能减少CPU对线程的切换,所以要使线程数尽可能少; 线程数 = CPU核心数 + 1; CPU核心数:Runtime.getRuntime().availableProcessors(); 这里的+1,比CPU核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响,一旦任务暂停,CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间;当然+1也可能导致多一个cpu上下文切换; * **2、IO密集型:** - 任务需要进行大量的IO操作,那么就会有大量的阻塞等待, - CPU大部分时间是在阻塞,该情况下应尽可能减少阻塞所带来的消耗, - 所以要使线程数尽可能多; 公式:线程数 = CPU核心数 * 2 * **3、 另外的公式** -** - 线程数 =((线程等待时间+线程CPU时间)/ 线程CPU时间 )* CPU核心数; - ** 比如平均每个线程CPU运行时间为0.4s,线程等待时间为0.6s,CPU核心数为8, 那么根据上面公式计算:((0.6+0.4)/0.4)*8=20; 线程等待时间所占比例越高,需要越多线程,线程CPU时间所占比例越高, 需要越少线程; #### 这些公式可以吗? #### ![在这里插入图片描述][45f9b6c0d0ed4db489e5433f95148b9e.png] 综上,线程池大小的设置没有固定公式,不能设置过大也不能设置过小,我们可以根据业务场景,从上面三个公式中选择一个得到一个大概的线程数量,然后通过压测,逐渐“增大线程数量”和“减小线程数量”,然后观察整体的处理时间变化,最终确定一个具体的线程数量,让任务处理速度最快; #### 2核cpu示例: #### //基于Executor框架实现线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 4, 4, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(256), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); threadPoolExecutor.execute(() -> System.out.println(1)); 任务执行一般是100-300ms左右,取中间值200ms,客户端能容忍10s超时; 10s \* 1000 = 10000ms / 200ms = 50个 \* 4个线程 = 200个 -->256; **maximumPoolSize**最大线程数在生产环境上我们往往设置成**corePoolSize**一样,这样可以减少在处理过程中创建线程的开销; **线程池的任务队列本来起缓冲作用**,任务队列长度取决服务端处理能力以及客户端能容忍的超时时间;如果响应时间要求较高的系统可以设置为任务队列长度为0; 任务执行时间短,可以把等待队列弄大一点,任务执行耗时长,等待队列应该调小一点; ### 1.11动态线程池 ### 线程池大小的设置没有完美公式,实际评估和压测得到的合理线程池参数在实际线上环境运行过程中也许不一定合理,怎么样快速地修改线程池的参数呢? ![在这里插入图片描述][8237408e5f0a4035979a7b63f996d4e6.png] #### Spring Cloud Alibaba版本说明 #### [https://github.com/alibaba/spring-cloud-alibaba/wiki/][https_github.com_alibaba_spring-cloud-alibaba_wiki] #### Nacos运行环境部署 #### Nacos官网:[https://nacos.io/][https_nacos.io] * 1、下载nacos最新的二进制压缩包; 下载地址:https://github.com/alibaba/nacos/releases * 2、解压下载下来的nacos最新的二进制压缩包; tar -zxvf nacos-server-1.4.2.tar.gz cd nacos/bin * 3、启动nacos server ./startup.sh -m standalone 注:单机环境必须带-m standalone参数启动,否则无法启动,不带参数启动的是集群环境; * 4、启动日志:/usr/local/nacos/logs/start.out * 5、访问:http://ip:8848/nacos 默认用户名密码:nacos/nacos **【衔接下一章[【并发编程七:Java中的线程池(4)-线程池规范、监控、关闭】][Java_4_-]】** [Java_2_-]: https://blog.csdn.net/weixin_43333483/article/details/124556402?spm=1001.2014.3001.5502 [45f9b6c0d0ed4db489e5433f95148b9e.png]: https://img-blog.csdnimg.cn/45f9b6c0d0ed4db489e5433f95148b9e.png [8237408e5f0a4035979a7b63f996d4e6.png]: https://img-blog.csdnimg.cn/8237408e5f0a4035979a7b63f996d4e6.png [https_github.com_alibaba_spring-cloud-alibaba_wiki]: https://github.com/alibaba/spring-cloud-alibaba/wiki/ [https_nacos.io]: https://nacos.io/ [Java_4_-]: https://blog.csdn.net/weixin_43333483/article/details/124557527?spm=1001.2014.3001.5502
相关 Java并发编程实战:线程池的应用实例 《Java并发编程实战:线程池的应用实例》是一本专注于Java并发编程,特别是线程池应用的实践书籍。 书中首先会系统地介绍Java并发编程的基础知识,包括线程创建、同步原语等 谁借莪1个温暖的怀抱¢/ 2024年09月11日 22:45/ 0 赞/ 19 阅读
相关 Java并发编程中的线程池应用实例 在Java并发编程中,线程池是一种常用的资源管理工具,它可以复用已创建的线程,降低新创建线程带来的开销。 以下是一个简单的线程池应用实例: ```java import j 太过爱你忘了你带给我的痛/ 2024年09月10日 19:24/ 0 赞/ 15 阅读
相关 【并发编程六:Java中的线程池(3)-线程池的应用】 【衔接上一章 [【并发编程五:Java中的线程池(2)-线程的实现原理】][Java_2_-]】 学习路线 1.9工作中线程池的应用 1 ╰半夏微凉°/ 2023年10月09日 14:09/ 0 赞/ 12 阅读
相关 Java 并发编程:线程池的使用 转载:[https://www.cnblogs.com/dolphin0520/p/3932921.html][https_www.cnblogs.com_dolphin052 喜欢ヅ旅行/ 2022年05月16日 04:28/ 0 赞/ 198 阅读
相关 Java并发编程——线程池的使用 > 转载于:[Java并发编程:线程池的使用][Java] > > 本文基于JDK 1.6,在高版本JDK中源码有所出入 一、Java中的ThreadPoolEx 悠悠/ 2022年05月10日 09:44/ 0 赞/ 216 阅读
相关 java并发编程-线程池 为什么要用线程池 1. 降低资源消耗 2. 提高响应速度 T1: 线程创建的时间 T2:工作任务运行额时间 T3: 线程销毁时间 3. 提高了线程的可管理性 绝地灬酷狼/ 2022年04月24日 07:26/ 0 赞/ 297 阅读
相关 Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这 Dear 丶/ 2022年03月15日 19:14/ 0 赞/ 234 阅读
相关 并发编程-线程池 newfixedthreadpool(固定线程数量的线程池) 可控制线程最大并发数,超出的线程会在队列中等待 ExecutorService newFixedT 小咪咪/ 2022年02月22日 13:14/ 0 赞/ 317 阅读
还没有评论,来说两句吧...