Java线程池的那些事(Java线程池详解:从入门到进阶应用指南)
原创
一、Java线程池简介
Java线程池是一种用于管理线程的工具,它能够有效地管理线程的生命周期,尽大概缩减损耗程序性能。在Java中,线程池的实现核心是通过`java.util.concurrent`包中的`Executor`框架。使用线程池可以避免频繁创建和销毁线程的开销,同时能够合理地复用线程资源。
二、线程池的核心接口和类
Java线程池的核心接口和类如下:
- `Executor`:线程池的顶层接口,只有一个`execute(Runnable)`方法,用于提交任务。
- `ExecutorService`:扩展了`Executor`接口,添加了多个功能方法,如`submit()`、`shutdown()`等。
- `AbstractExecutorService`:实现了`ExecutorService`接口的抽象类,提供了大部分方法的实现。
- `ThreadPoolExecutor`:`AbstractExecutorService`的实现类,是线程池的核心实现。
- `ScheduledThreadPoolExecutor`:扩展了`ThreadPoolExecutor`,用于实现定时任务。
- `Executors`:提供了创建线程池的工厂方法。
三、线程池的创建
Java提供了`Executors`类,它包含了一系列工厂方法用于创建不同类型的线程池:
ExecutorService executorService = Executors.newFixedThreadPool(10); // 创建一个固定大小为10的线程池
ExecutorService executorService1 = Executors.newSingleThreadExecutor(); // 创建一个单线程的线程池
ExecutorService executorService2 = Executors.newCachedThreadPool(); // 创建一个可缓存的线程池
ExecutorService executorService3 = Executors.newScheduledThreadPool(10); // 创建一个定时任务的线程池
四、线程池的参数
创建线程池时,可以设置以下参数:
- `corePoolSize`:线程池的基本大小。
- `maximumPoolSize`:线程池最大线程数。
- `keepAliveTime`:当线程数大于核心线程数时,这是多余空闲线程在终止前等待新任务的最长时间。
- `unit`:`keepAliveTime`的时间单位。
- `workQueue`:用来存放任务的队列。
- `threadFactory`:创建线程的工厂。
- `handler`:拒绝策略,当任务太多无法处理时,采取的策略。
五、线程池的工作流程
线程池的工作流程如下:
- 当提交一个任务时,线程池首先检查是否有空闲的核心线程。
- 如果有,则立即执行该任务。
- 如果没有,则将任务放入队列。
- 如果队列已满,则创建一个新线程,直到约为最大线程数。
- 如果约为最大线程数,则采用拒绝策略处理新提交的任务。
六、线程池的拒绝策略
当线程池无法处理新提交的任务时,会采用拒绝策略。Java提供了以下四种拒绝策略:
- `AbortPolicy`:抛出`RejectedExecutionException`异常。
- `CallerRunsPolicy`:调用任务的`run()`方法,在调用者线程中直接执行该任务。
- `DiscardPolicy`:默默丢弃无法处理的任务,不抛出异常。
- `DiscardOldestPolicy`:丢弃队列中最旧的任务,然后尝试执行新提交的任务。
七、线程池的进阶应用
在实际开发中,我们大概会遇到以下几种场景:
7.1 批量提交任务
使用`ExecutorService`的`invokeAll()`方法可以批量提交任务,并等待所有任务完成。
List
> tasks = new ArrayList<>(); tasks.add(() -> "Task1");
tasks.add(() -> "Task2");
tasks.add(() -> "Task3");
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
List
> results = executorService.invokeAll(tasks); for (Future
result : results) { System.out.println(result.get());
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
7.2 分页提交任务
当任务非常多时,可以分批次提交任务。
public void submitTasks(List
tasks, int pageSize) { ExecutorService executorService = Executors.newFixedThreadPool(10);
int totalSize = tasks.size();
for (int i = 0; i < totalSize; i += pageSize) {
int endIndex = Math.min(i + pageSize, totalSize);
List
subList = tasks.subList(i, endIndex); for (Runnable task : subList) {
executorService.submit(task);
}
}
executorService.shutdown();
}
7.3 定时任务
使用`ScheduledThreadPoolExecutor`可以方便地实现定时任务。
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.schedule(() -> System.out.println("Run after 1 second"), 1, TimeUnit.SECONDS);
executor.shutdown();
八、总结
Java线程池是Java并发编程中非常重要的一个工具,它能够有效地管理线程的生命周期,尽大概缩减损耗程序性能。通过合理地配置线程池参数和选择合适的拒绝策略,我们可以使程序更加高效地运行。同时,掌握线程池的高级应用,如批量提交任务、分页提交任务和定时任务,能够帮助我们更好地应对实际开发中的各种场景。