线程池的底层是基于线程和任务队列来实现的,创建线程池的创建方式通常有以下两种:
图片
Spring 内置的线程池 ThreadPoolTaskExecutor 的使用示例如下:
@Configuration
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(5);
// 最大线程数
executor.setMaxPoolSize(10);
// 队列容量
executor.setQueueCapacity(20);
// 线程池维护线程所允许的空闲时间
executor.setKeepAliveSeconds(60);
// 线程池对拒绝任务(无线程可用)的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
1.线程池工作流程
当有任务来了之后,线程池的执行流程是这样的:
如下图所示:
图片
2.拒绝策略
当线程池无法接受新任务时,会触发拒绝策略,内置的拒绝策略有四种:
除了内置的拒绝策略之外,我们还可以设置自定义拒绝策略,它的实现如下:
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 在这里处理拒绝的任务
System.err.println("任务被拒绝执行: " + r.toString());
// 可以选择记录日志、抛出自定义异常或采取其他措施
// 例如,可以将任务保存到某个队列中,稍后再尝试重新执行
}
}
使用自定义拒绝策略:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 配置线程池参数
int corePoolSize = 5;
int maximumPoolSize = 10;
long keepAliveTime = 60L;
TimeUnit unit = TimeUnit.SECONDS;
int queueCapacity = 25;
// 创建一个阻塞队列
ArrayBlockingQueue workQueue =
new ArrayBlockingQueue(queueCapacity);
// 创建 ThreadPoolExecutor 实例
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
new CustomRejectedExecutionHandler() // 使用自定义的拒绝策略
);
// 提交任务
for (int i = 0; i {
System.out.println("执行任务: " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");
try {
Thread.sleep(1000); // 模拟耗时任务
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 关闭线程池(这不会立即停止所有正在执行的任务)
executor.shutdown();
}
}
课后反思
实际项目中线程池会使用哪种拒绝策略?为什么?线程池是通过什么机制来创建线程的?线程池创建线程时可以设置哪些属性?