ThreadPoolExecutor线程池组成:
ThreadPoolExecutor构造器
三大核心参数解释:
- corePoolSize - 核心线程数
- maximumPoolSize - 最大线程数
- keepAliveTime - 空闲线程存活时间
核心线程数通用计算公式:(公式只是合适的理论值,一切以实际为主)
1.CPU 密集型的程序 - 核心数 + 1
2. I/O 密集型的程序 - 核心数 * 2)
最大线程数计算公式:核心线程数 * 2
线程池拒绝策略的触发场景
当提交任务数大于 corePoolSize 的时候,会优先将任务放到 workQueue 阻塞队列中。
当阻塞队列饱和后,会扩充线程池中线程数,直到达到 maximumPoolSize 最大线程数配置。
此时,再多余的任务,则会触发线程池的拒绝策略。当提交的任务数大于(workQueue.size() + maximumPoolSize ),就会触发线程池的拒绝策略处理器RejectedExecutionHandler执行对应的处理方法。
线程池的拒绝策略:
AbortPolicy
触发会抛出异常,中止任务。抛出RejectedExecutionException拒绝执行异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行。
测试代码
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class AbortPolicyMain {
public static void main(String[] args) {
//核心线程数 = 电脑核数 + 1 = 4核 + 1
int corePoolSize = 5;
//最大线程数 8
int maximumPoolSize = 8;
//空闲线程最大存活时间
long keepAliveTime = 5;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10);
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.SECONDS, workQueue, handler);
int count = 1;
while (count < 100) {
try {
int finalCount = count;
threadPoolExecutor.execute(new Thread(
() -> System.out
.println("当前次数: " + finalCount + ",正常运行线程" + Thread.currentThread().getName() + "...")));
} catch (Exception e) {
e.printStackTrace();
}
count++;
}
//注意:最后关闭线程池
threadPoolExecutor.shutdown();
}
}
CallerRunsPolicy
会使用调用者当前线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。
测试代码
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CallerRunsPolicyMain {
public static void main(String[] args) {
//核心线程数 = 电脑核数 + 1 = 4核 + 1
int corePoolSize = 5;
//最大线程数 8
int maximumPoolSize = 8;
//空闲线程最大存活时间
long keepAliveTime = 5;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10);
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.SECONDS, workQueue, handler);
int count = 1;
while (count < 100) {
try {
int finalCount = count;
threadPoolExecutor.execute(new Thread(
() -> System.out
.println("当前次数: " + finalCount + ",正常运行线程" + Thread.currentThread().getName() + "...")));
} catch (Exception e) {
e.printStackTrace();
}
count++;
}
//注意:最后关闭线程池
threadPoolExecutor.shutdown();
}
}
DiscardPolicy
直接丢弃,啥也不干
DiscardOldestPolicy
当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入
总结:
要根据具体的场景需求,采取合适的策略
使用线程池的优点:
- 降低资源消耗:通过重复利用已创建的线程降低创建/销毁线程的消耗
- 提高响应速度:当任务来时,不用等线程创建,直接通过线程池已创建的线程直接执行
- 便于管理:线程池可以统一分配,方便调优和监控线程。
文章评论