为什么用线程池,优势
线程池做的工作主要就是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程的数量超过了最大数量,超过数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
主要特点:线程复用;控制最大并发数;管理线程。
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗;
第二:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即工作;
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以同一的分配、调优和监控。
JDK编码实现
package com.interview.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @Author leijs
* @date 2022/3/29
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
// 固定线程数的池子,线程池有5个线程
ExecutorService threadPool = Executors.newFixedThreadPool(5);
// ExecutorService threadPool = Executors.newSingleThreadExecutor();
// ExecutorService threadPool = Executors.newCachedThreadPool();
// 执行短周期的任务
// ExecutorService threadPool = Executors.newScheduledThreadPool(2);
try {
for (int i = 0; i < 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t 办理业务");
});
}
} catch (Exception e) {
} finally {
threadPool.shutdown();
}
}
}
底层:ThreadPoolExecutor
注意:LinkedBlockingQueue
线程池七大参数
参数 | 解释 |
---|---|
corePoolSize | 线程池中的核心线程数。 - 在创建了线程池后,当有请求任务来之后,就会安排池中的线程去执行请求任务 - 当线程中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列中。 |
maximumPoolSize | 线程池能够容纳同时执行的最大线程数,此值必须大于等于1 |
keepAliveTime | 多余的空闲线程的存活时间。当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。 - 默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize |
TimeUnit | keepAliveTime的单位 |
workQueue | 任务队列(阻塞队列);被提交但尚未被执行的任务 |
Executors.defaultThreadFactory() | 表示生成线程池中工作线程的线程工厂,用于创建线程,一般用默认的即可 |
defaultHandler | > private static final RejectedExecutionHandler defaultHandler = new AbortPolicy(); |
拒绝策略:表示当队列满了并且工作线程大于等于最大线程数(maximumPoolSize)
- AbortPolicy
- DiscardPolicy
- CallerRunsPolicy
- DiscardOldestPolicy
|
线程池工作原理
拒绝策略
内置的拒绝策略都实现了RejectedExecutionHandler接口
AbortPolicy(默认)
直接抛出异常RejectedExecutionException, 异常阻止系统正常运行
CallRunsPolicy
“调用者运行”一种调节机制,该策略不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量
DiscardOldestPolicy
抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
DiscardPolicy
直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案
工作中使用哪一种线程池?
JDK默认的四种都不用
结论:自己定义。
ExecutorService executorService = new ThreadPoolExecutor(2,
10, 60, TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
线程池参数设置
- CPU密集型
指该任务需要大量的运算,没有阻塞,CPU一直运行。
一般公式:CPU核数+1 的线程池
- IO密集型
并不知一直在执行的任务,IO会有大量的阻塞。尽可能配置多: CPU核数 * 2
参考核数: CPU核数 / (1 - 阻塞系数)
阻塞系数 0.8~0.9 一般乐观一点取个0.9