线程池 一时失言乱红尘 2022-10-23 11:25 13阅读 0赞 ### 文章目录 ### * 一、线程池简介 * * 1.1 线程池介绍 * 1.2 常用线程池的使用 * 二、线程池调优 * * 2.1 线程池底层工作原理 * 2.2 线程池七大重要参数 * 2.3 线程池拒绝策略 * 2.4 实际工作中使用哪种线程池? * 2.5 合理配置线程池 # 一、线程池简介 # ## 1.1 线程池介绍 ## 线程池主要是控制运行线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。 主要特点是: 线程复用、控制最大并发数、管理线程。 线程池的优点: 1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗; 2. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行; 3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。 ## 1.2 常用线程池的使用 ## `Java`中的线程池是通过`Executor`框架实现的,该框架中用到了`Executor`,`Executors`、`ExecutorService`、`ThreadPoolExecutor`这几个类。 **① Executors.newFixedThreadPool(int)** 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。`newFixedThreadPool`创建的线程池`corePoolSize`和`maximumPoolSize`值是相等的,它使用的`LinkedBlockingQueue`。执行长期的任务,性能好很多。 **② Executors.newSingleThreadExecutor()** 创建一个单线程化的线程池,它只会唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。一个任务一个任务执行的场景。 **③ Executors.newCachedThreadPool()** `newSingleThread`将`corePoolSize`和`maximumPoolSize`都设置为1,它使用的是`LinkedBlockingQueue`。适用:执行很多短期异步的小程序或者负载较轻的服务器。 **④ Executors.newWorkStealingPool(int)** `java8`新增,使用目前机器上可用的处理器作为它的并行级别。 # 二、线程池调优 # ## 2.1 线程池底层工作原理 ## ![在这里插入图片描述][20210306104150360.png] ① 在创建了线程池后,等待提交过来的任务请求。 ② 当调用`execute()`方法添加一个请求任务时,线程池会做如下判断: 1. 如果正在运行的线程数量下雨`corePoolSize`,那么马上创建马上创建线程运行这个任务; 2. 如果正在运行的线程数量大于或等于`corePoolSize`,那么将这个任务放入队列; 3. 如果这个时候队列满了且正在运行的线程数量还小于`maximumPoolSize`,那么还是要创建非核心线程立刻运行这个任务; 4. 如果队列满了且正在运行的线程数量大于或等于`maximumPoolSize`,那么线程池会启动饱和拒绝策略来执行。 ③ 当一个线程完成任务时,它会从队列中取下一个任务来执行。 ④ 当一个线程无事可做超过一定的时间(`keepAlilveTime`)时,线程池会判断: 1. 如果当前运行的线程数大于`corePoolSize`,那么这个线程就被停掉。 2. 所以线程池的所有任务完成后它最终会收缩到`corePoolSize`的大小 ## 2.2 线程池七大重要参数 ## `Executors`的实现的多种线程池都是通过`ThreadPoolExecutor`实现的,通过调整其不同的参数达到实现不同线程池的目的。 ![在这里插入图片描述][2021030610540079.png] <table> <thead> <tr> <th>参数</th> <th>说明</th> </tr> </thead> <tbody> <tr> <td>corePoolSize</td> <td>线程池中的常驻核心线程数</td> </tr> <tr> <td>maximumPoolSize</td> <td>线程池能够容纳同时执行的最大线程数,此值必须大于等于1.</td> </tr> <tr> <td>keepAliveTime</td> <td>多余的空闲线程的存活时间。当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。</td> </tr> <tr> <td>unit</td> <td>keepAliveTime的单位</td> </tr> <tr> <td>workQueue</td> <td>任务队列,被提交但尚未被执行的任务。</td> </tr> <tr> <td>threadFactory</td> <td>表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可。</td> </tr> <tr> <td>handler</td> <td>拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数。</td> </tr> </tbody> </table> ## 2.3 线程池拒绝策略 ## 等待队列也满了,再也塞不下新任务了,同时线程池中的max线程也达到了,无法继续为新的任务服务。这时候就需要拒绝策略机制合理的处理这个问题。 `Java`内置的拒绝策略如下,其均实现了`RejectedExecutionHandler`接口: * **AbortPolicy(默认)**:直接跑出`RejectedExecutionException`异常阻止系统正常运行。 * **CallerRunsPolicy**:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。 * **DiscardOldestPolicy**:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务。 * **DiscardPolicy**:直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案。 ## 2.4 实际工作中使用哪种线程池? ## 实际公路中不使用`Java`自带的线程池,使用自定义线程池。 public class MyThreadPool { public static void main(String[] args) { ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); try { for (int i = 0; i < 10; i++) { threadPool.execute(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "使用了线程池"); }); } } finally { threadPool.shutdown(); } } } ## 2.5 合理配置线程池 ## **①CPU密集型** `CPU`密集的意思是该任务需要大量的运算,而没有阻塞,`CPU`一直全速运行。 `CPU`密集型任务配置尽可能少的线程数量:一般公式为: `CPU`核数+1个线程的线程的线程池 。 **②IO密集型** 在单线程上运行`IO`密集型的任务会导致浪费大量的`CPU`运算能力浪费在等待。所以`IO`密集型任务中使用多线程可以大大的加速程序运行,即使在单核`CPU`上,这种加速主要就是利用了被浪费掉的阻塞时间。 `IO`密集型时,大部分线程都阻塞,故需要多配置线程数:参考公式:`CPU`核数/1-阻塞系数,阻塞系数在0.8-0.9之间。 [20210306104150360.png]: /images/20221023/6ee36c7bf9704cc1b5e8a543d1427d19.png [2021030610540079.png]: /images/20221023/35990584acac441fbe179371d5c88af6.png
相关 Java 线程池、Runnable线程池、Callable线程池 线程池: 其实就是一个容纳多个线程的容器,其中的线程可以反复的使用,省去了频繁创建和销毁过程对象的操作,无需反复创建线程面消耗过多资源。 为什么要用线程池: 合理 青旅半醒/ 2023年02月26日 12:30/ 0 赞/ 112 阅读
相关 线程、线程池 创建线程的3种方法: package com.frank.threadPool.createThread; / @author 小石潭记 布满荆棘的人生/ 2022年10月22日 04:27/ 0 赞/ 434 阅读
相关 线程池 1.所谓线程池,就是程序的初始化阶段,就预先创建一批线程,每个线程都做好准备干活; 2.然后有一个任务列表,一开始为空,当有任务来了,就往任务列表里面添加;这个任务列表 痛定思痛。/ 2022年06月13日 13:22/ 0 赞/ 362 阅读
相关 线程池 西施越溪女,明艳光云海 最近用线程池和不用线程池做了个速度的测试,在这里备注下: 结果是速度不相上下; public static void main(Str 妖狐艹你老母/ 2022年05月20日 02:35/ 0 赞/ 323 阅读
相关 线程池 线程池 Java里面线程池的顶级接口是 java.util.concurrent.Executor , 但是严格意义上讲 Executor并不是一个线程池,而只是一个 迈不过友情╰/ 2022年03月06日 14:34/ 0 赞/ 442 阅读
相关 线程池 线程池 > 从字面义上来讲,是指管理一组同构工作线程的资源池。线程池是与工作队列密切相关的,其中在工作队列中(Worker Queue)保存了所有等待执行的任务。工作者( 清疚/ 2021年12月11日 03:35/ 0 赞/ 425 阅读
相关 线程池 可preStart一个或全部core thread 0,小于core则来一个任务建一个线程(firstTask),队列,额外线程,拒绝 一个AtomicInteger的 今天药忘吃喽~/ 2021年11月23日 03:40/ 0 赞/ 450 阅读
相关 线程池 1、先创建线程池 import java.util.concurrent.ArrayBlockingQueue; import java.util.concu 拼搏现实的明天。/ 2021年11月09日 14:28/ 0 赞/ 459 阅读
还没有评论,来说两句吧...