文章目录
- 前言
- 线程池的基本概念
- 1.什么是线程池?
- 2. 线程池的主要组件
- Java 线程池的实现类
- 1、ThreadPoolExecutor
- 2、Executors 工具类
- 线程池的配置与调优
- 1、核心线程数和最大线程数
- 2、工作队
- 3、 拒绝策略
- 实战案例
- 案例 1:批量处理文件上传
- 案例 2:定时任务调度
- 案例 3:异步任务处理
- 总结
前言
线程池是 Java 并发编程中的一个重要概念,它通过复用已创建的线程来减少线程创建和销毁的开销,提高应用程序的性能。本文将详细介绍 Java 线程池的工作原理、常用配置,并结合实战案例展示其应用。
线程池的基本概念
1.什么是线程池?
线程池是一种多线程处理形式,处理过程中将任务添加到队列中,并在线程空闲时执行任务。线程池的核心思想是预先创建并维护一定数量的线程,避免频繁创建和销毁线程带来的资源消耗。
2. 线程池的主要组件
核心线程数(Core Pool Size):线程池中保持的最小线程数,即使这些线程处于空闲状态。
最大线程数(Maximum Pool Size):线程池中允许的最大线程数。
工作队列(Work Queue):用于保存等待执行的任务队列。
线程工厂(Thread Factory):用于创建新线程的工厂类,默认使用 Executors.defaultThreadFactory()。
拒绝策略(Rejected Execution Handler):当线程池无法处理新任务时的处理策略。
Java 线程池的实现类
Java 提供了多种线程池实现类,最常用的是 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor。此外,Executors 工具类提供了便捷的静态方法来创建不同类型的线程池。
1、ThreadPoolExecutor
ThreadPoolExecutor 是 Java 中最常用的线程池实现类,提供了丰富的配置选项。
构造函数
public ThreadPoolExecutor(int corePoolSize, //核心线程数int maximumPoolSize, //最大线程数long keepAliveTime, //线程空闲时间,超过此时间的空闲线程将被终止TimeUnit unit, //keepAliveTime 的时间单位BlockingQueue<Runnable> workQueue, //任务队列ThreadFactory threadFactory, //线程工厂RejectedExecutionHandler handler) //拒绝策略
2、Executors 工具类
Executors 提供了一些静态方法来简化线程池的创建:
newFixedThreadPool(int nThreads):创建一个固定大小的线程池。
newCachedThreadPool():创建一个根据需要创建新线程的线程池。
newSingleThreadExecutor():创建一个单线程的线程池。
newScheduledThreadPool(int corePoolSize):创建一个支持定时和周期性任务执行的线程池。
线程池的配置与调优
1、核心线程数和最大线程数
核心线程数:应根据 CPU 核心数和任务类型设置。对于 CPU 密集型任务,核心线程数可以设置为 CPU 核心数;对于 I/O 密集型任务,可以适当增加。
最大线程数:应根据系统资源和任务负载动态调整,避免过多线程导致上下文切换频繁。
2、工作队
常见的工作队列类型包括:
SynchronousQueue:不存储元素的阻塞队列,直接将任务交给线程处理。
LinkedBlockingQueue:基于链表的有界或无界阻塞队列。
ArrayBlockingQueue:基于数组的有界阻塞队列。
PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
3、 拒绝策略
常见的拒绝策略包括:
AbortPolicy:抛出 RejectedExecutionException 异常。
CallerRunsPolicy:由调用线程执行任务。
DiscardPolicy:直接丢弃任务。
DiscardOldestPolicy:丢弃队列中最旧的任务,然后尝试重新提交当前任务。
实战案例
案例 1:批量处理文件上传
假设我们有一个 Web 应用程序,用户可以批量上传多个文件。为了提高处理速度,我们可以使用线程池来并发处理文件上传请求。
示例代码
/*** FileUploadService* @author senfel* @version 1.0* @date 2025/1/3 14:52*/
@Service
public class FileUploadService {private final ExecutorService executor = new ThreadPoolExecutor(4, // 核心线程数10, // 最大线程数60L, TimeUnit.SECONDS, // 空闲线程存活时间new LinkedBlockingQueue<>(100), // 工作队列Executors.defaultThreadFactory(), // 线程工厂new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略);/*** uploadFiles* @param files* @author senfel* @date 2025/1/3 14:54 * @return void*/public void uploadFiles(List<File> files) {for (File file : files) {executor.submit(() -> processFile(file));}}private void processFile(File file) {try {// 模拟文件处理逻辑System.out.println("Processing file: " + file.getName());Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}/*** shutdown* @author senfel* @date 2025/1/3 14:54 * @return void*/public void shutdown() {executor.shutdown();try {if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {executor.shutdownNow();}} catch (InterruptedException e) {executor.shutdownNow();}}
}
案例 2:定时任务调度
假设我们需要定期清理过期的日志文件。可以使用 ScheduledThreadPoolExecutor 来实现定时任务调度。
示例代码
/*** LogCleanupService* @author senfel* @version 1.0* @date 2025/1/3 14:55*/
@Service
public class LogCleanupService {private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);/*** startLogCleanup* @author senfel* @date 2025/1/3 14:56 * @return void*/public void startLogCleanup() {Runnable cleanupTask = () -> {try {// 模拟日志清理逻辑System.out.println("Cleaning up logs...");Thread.sleep(5000); // 模拟耗时操作} catch (InterruptedException e) {Thread.currentThread().interrupt();}};// 每隔 1 小时执行一次日志清理任务scheduler.scheduleAtFixedRate(cleanupTask, 0, 1, TimeUnit.HOURS);}/*** shutdown* @author senfel* @date 2025/1/3 14:57 * @return void*/public void shutdown() {scheduler.shutdown();try {if (!scheduler.awaitTermination(800, TimeUnit.MILLISECONDS)) {scheduler.shutdownNow();}} catch (InterruptedException e) {scheduler.shutdownNow();}}
}
案例 3:异步任务处理
假设我们有一个订单处理系统,需要异步处理订单通知。可以使用 CompletableFuture 结合线程池来实现异步任务处理。
示例代码
/*** OrderNotificationService* @author senfel* @version 1.0* @date 2025/1/3 14:57*/
@Service
public class OrderNotificationService {private final ExecutorService executor = Executors.newFixedThreadPool(5);/*** sendNotification* @param orderId* @author senfel* @date 2025/1/3 14:59* @return java.util.concurrent.CompletableFuture<java.lang.Void>*/public CompletableFuture<Void> sendNotification(Long orderId) {return CompletableFuture.runAsync(() -> {try {// 模拟发送通知逻辑System.out.println("Sending notification for order: " + orderId);Thread.sleep(2000); // 模拟耗时操作} catch (InterruptedException e) {Thread.currentThread().interrupt();}}, executor);}/*** shutdown* @author senfel* @date 2025/1/3 14:59* @return void*/public void shutdown() {executor.shutdown();try {if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {executor.shutdownNow();}} catch (InterruptedException e) {executor.shutdownNow();}}
}
总结
方案 | 优点 | 确定 | 适用场景 |
---|---|---|---|
ThreadPoolExecutor | 配置灵活,功能强大; | 需要手动管理线程池生命周期 | 适用于复杂任务调度 |
Executors | 工具类使用简单,快速创建线程池; | 默认配置可能不适合所有场景 | 适用于快速开发 |
ScheduledThreadPoolExecutor | 支持定时和周期性任务; | 功能相对单一 | 适用于定时任务调度 |
CompletableFuture | 异步编程模型,易于组合; | 学习曲线较陡 | 适用于异步任务处理 |
在实际的编码场景中,我们通过合理配置和使用线程池,可以显著提升 Java 应用程序的性能和响应速度。