目录
3. ScheduledExecutorService 接口
6. ScheduledThreadPoolExecutor 类
线程池优势
- 统一接口:所有线程池都实现了ExecutorService接口,可以通过相同的方法进行管理,如submit、execute、shutdown等。
- 线程复用:所有线程池都重用内部的线程来执行多个任务,以减少创建和销毁线程的开销。
- 任务排队:每个线程池都有一个内部的任务队列,用于管理等待执行的任务。
创建方式
Executors
newCachedThreadPool
特性:
- 创建一个可缓存的线程池。
- 如果线程池中的线程有空闲且超过60秒没有被使用,它们将被终止并移除。
- 如果线程池中的线程都在使用,新任务会创建新的线程来处理。
应用场景:适用于大量短期异步任务的小规模并发。需要快速响应任务。
示例
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "在运行");
});
}
executorService.shutdown();
}
newFixedThreadPool
特性:
- 创建一个定长的线程池,最多同时有nThreads个线程。
- 超过这个数量的任务会在队列中等待。
应用场景:适用于固定并发数的场景,比如处理固定数量的长期任务。
参数:nThreads - 线程池中的线程数量。
示例
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "在运行");
});
}
executorService.shutdown();
}
newScheduledThreadPool
特性:
- 创建一个支持定时和周期性任务执行的线程池。
- 核心线程数为corePoolSize。
应用场景:适用于需要周期性或定时执行任务的场景,比如定时备份、定时任务调度。
参数:corePoolSize - 核心线程数量。
public static void main(String[] args) {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 10; i++) {
executorService.schedule(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "在运行");
}, 3, TimeUnit.SECONDS);
}
executorService.shutdown();
}
newSingleThreadExecutor
特性:
- 创建一个单线程的线程池。
- 确保所有任务按顺序执行。
- 如果线程意外终止,会创建一个新的线程继续执行后续任务。
应用场景:适用于需要顺序执行任务的场景,比如顺序写入日志。
示例
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "在运行");
});
}
executorService.shutdown();
}
newWorkStealingPool
特性:
- 创建一个工作窃取线程池。
- 默认使用CPU核数作为并行级别。
- 适用于分而治之的大量任务,能充分利用多核CPU。
应用场景:适用于大规模并行任务,比如并行流的任务处理。
参数:可以不传参数,默认使用CPU核数。也可以传递并行级别。
示例
public static void main(String[] args) {
ExecutorService executorService = Executors.newWorkStealingPool();
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "在运行");
});
}
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ThreadPoolExecutor
使用ThreadPoolExecutor来创建线程,可以更细粒度的控制线程池的行为。
示例
public static void main(String[] args) {
int corePoolSize = 2;
int maximumPoolSize = 4;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
handler);
for (int i = 0; i < 10; i++) {
threadPoolExecutor.execute(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + " 正在运行");
try {
Thread.sleep(2000); // 模拟任务执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
threadPoolExecutor.shutdown();
}
参数解释
- corePoolSize:核心线程数。即使线程是空闲的,这些线程也会一直存活,除非设置了allowCoreThreadTimeOut。
- maximumPoolSize:最大线程数。当任务队列已满且线程数小于 maximumPoolSize 时,会创建新的线程来处理任务。
- keepAliveTime:当线程数大于 corePoolSize 时,空闲线程的存活时间。超过这个时间,空闲线程会被终止。
- unit:keepAliveTime 的时间单位。
- workQueue:任务队列,用于保存等待执行的任务。
- threadFactory:线程工厂,用于创建新线程。可以自定义线程工厂以设置线程名称、优先级等。
- handler:拒绝策略。当任务无法被线程池接受时,会执行这个策略。
拒绝策略
- AbortPolicy:抛出 RejectedExecutionException 异常。
- CallerRunsPolicy:由调用线程执行该任务。
- DiscardPolicy: 直接丢弃任务,不抛出异常。
- DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试执行新的任务。
核心线程数的设定
- CPU密集型:CPU核心数 + 1
- IO密集型:CPU核心数 * 2
任务加入线程池规则
- 不管线程池中是否有空闲线程,只要运行线程数 < corePoolSize,那么新加入的任务都会直接创建新的线程处理。
- corePoolSize < 运行线程数 < maximumPoolSize
- workQueue已满:创建新线程处理任务
- workQueue未满:加入到workQueue
- 运行线程数 > maximumPoolSize
- workQueue已满:拒绝策略
- workQueue未满:加入到workQueue
其他常用方法
- getTaskCount():线程池已执行和未执行的任务总数
- getCompletedTaskCount():已完成的任务数量
- getPoolSize():线程池当前的线程数量
- getCorePoolSize():线程池核心线程数
- getActiveCount():当前线程池中正在执行任务的线程数量
ForkJoinPool
Java 7 引入的一个专门用于并行任务执行的线程池,特别适用于递归分治任务和工作窃取算法。
特性
- 工作窃取算法:ForkJoinPool 使用工作窃取算法,通过允许闲置的线程从忙碌的线程的任务队列中窃取工作来平衡负载。
- 适合并行计算:非常适合需要将大任务分解成小任务并行执行的场景。
- 管理复杂任务依赖:可以管理依赖关系复杂的任务,保证任务间的协调执行。
构造方法
- 默认构造方法:创建一个并行度等于 Runtime.getRuntime().availableProcessors() 的 ForkJoinPool。
- 指定并行度的构造方法:创建一个指定并行度的 ForkJoinPool。
- 高级构造方法:允许指定自定义的 ForkJoinWorkerThreadFactory、异常处理器和异步模式。
ForkJoinPool方法
- invoke:同步执行一个任务,等待任务完成并返回结果。
- execute:异步执行一个任务。
- submit:提交一个任务,返回一个 ForkJoinTask 对象,可用于进一步操作。
ForkJoinTask类型
- RecursiveTask<V>:有返回值的任务。
- RecursiveAction:没有返回值的任务。
应用场景
- 递归分治算法:如快速排序、归并排序。
- 并行流处理:如 Stream.parallel()。
- 大规模数据处理:如图像处理、矩阵运算。
示例
static class SumTask extends RecursiveTask<Long> {
// 阈值
private static final int THRESHOLD = 1000;
private long[] array;
private int start;
private int end;
SumTask(long[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
System.out.println("线程:" + Thread.currentThread().getName());
if (end - start <= THRESHOLD) {
long sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
return sum;
} else {
int middle = (start + end) / 2;
SumTask firstTask = new SumTask(array, start, middle);
SumTask secondTask = new SumTask(array, middle, end);
//异步执行
firstTask.fork();
secondTask.fork();
//合并结果
return firstTask.join() + secondTask.join();
}
}
}
public static void main(String[] args) {
int size = 10000;
long[] array = new long[size];
for (int i = 0; i < size; i++) {
array[i] = i + 1;
}
ForkJoinPool forkJoinPool = new ForkJoinPool();
SumTask sumTask = new SumTask(array, 0, size);
Long invoke = forkJoinPool.invoke(sumTask);
System.out.println("求和:" + invoke);
}
ScheduledThreadPoolExecutor
一个专门用于定时和周期性任务执行的线程池。
应用场景
- 定时任务:需要在指定时间后执行一次的任务。
- 周期性任务:需要定期执行的任务,如监控、数据同步等。
构造方法
- 核心线程数
public ScheduledThreadPoolExecutor(int corePoolSize)
- 核心线程数 + 线程工厂:
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory)
- 核心线程数 + 拒绝策略
public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler)
- 核心线程数 + 线程工厂 + 拒绝策略
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
示例
public static void main(String[] args) {
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2);
//定时执行一次性任务,延迟3秒执行
executor.schedule(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "执行一次性任务");
}, 3, TimeUnit.SECONDS);
//周期性任务:初始延迟2秒,每隔3秒执行一次
executor.scheduleAtFixedRate(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "执行周期性任务");
}, 2, 3, TimeUnit.SECONDS);
//周期性任务:初始延迟2秒,从上一个任务结束后,每隔3秒执行一次
executor.scheduleWithFixedDelay(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + "执行");
}, 2, 3, TimeUnit.SECONDS);
//在jvm关闭时,关闭线程池
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("====关闭线程池====");
executor.shutdown();
try {
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}));
}
线程池状态
- RUNNING
描述:线程池处于正常工作状态,可以接受新的任务并处理队列中的任务。
转换条件:初始状态,一旦线程池创建,它就进入 RUNNING 状态。
2. SHUTDOWN
描述:线程池不再接受新任务,但会继续处理队列中的任务。
转换条件:调用 shutdown() 方法后,线程池从 RUNNING 状态转换到 SHUTDOWN 状态。
3. STOP
描述:线程池不再接受新任务,并且会中断正在处理的任务。
转换条件:调用 shutdownNow() 方法后,线程池从 RUNNING 或 SHUTDOWN 状态转换到 STOP 状态。
4. TIDYING
描述:所有任务都已终止,工作线程数为零,线程池将要进入 TERMINATED 状态。
转换条件:当线程池在 SHUTDOWN 状态下,且队列为空,所有任务已执行完毕;或在 STOP 状态下,所有任务已中断,线程池将进入 TIDYING 状态。
5. TERMINATED
描述:线程池完全终止,所有资源都被回收。
转换条件:当线程池在 TIDYING 状态下,terminated() 钩子方法执行完毕后,进入 TERMINATED 状态。
线程池核心类
1. Executor 接口
功能
Executor 是一个简单的接口,用于分离任务的提交和任务的执行。它提供了一种解耦任务提交与任务如何执行的机制。
重要方法
- void execute(Runnable command): 执行提交的任务。
2. ExecutorService 接口
功能
ExecutorService 继承了 Executor 接口,增加了一些管理生命周期的方法和任务提交的方法。它允许我们管理线程池的生命周期,并提供任务的提交和管理。
重要方法
- void shutdown(): 启动有序关闭,不再接受新任务,但会执行已提交的任务。
- List<Runnable> shutdownNow(): 尝试停止所有正在执行的任务,并返回等待执行的任务列表。
- boolean awaitTermination(long timeout, TimeUnit unit): 等待所有任务完成或超时。
- <T> Future<T> submit(Callable<T> task): 提交一个返回值的任务,并返回一个 Future 表示任务的结果。
- <T> Future<T> submit(Runnable task, T result): 提交一个可运行的任务,并返回一个 Future 表示任务的结果。
- Future<?> submit(Runnable task): 提交一个可运行的任务,并返回一个 Future 表示任务的结果。
3. ScheduledExecutorService 接口
功能
ScheduledExecutorService 继承了 ExecutorService 接口,增加了用于调度命令在给定延迟后或定期执行的方法。
重要方法
- ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit): 在给定延迟后执行任务。
- <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit): 在给定延迟后执行任务,并返回 Future 表示任务的结果。
- ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit): 以固定速率定期执行任务。
- ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit): 以固定延迟定期执行任务。
4. AbstractExecutorService 类
功能
AbstractExecutorService 是 ExecutorService 的一个抽象实现,提供了一些基础设施以支持 submit 方法并转换任务为 Future。
重要方法
- Future<?> submit(Runnable task): 提交一个可运行的任务,并返回一个 Future 表示任务的结果。
- <T> Future<T> submit(Callable<T> task): 提交一个返回值的任务,并返回一个 Future 表示任务的结果。
5. ThreadPoolExecutor 类
功能
ThreadPoolExecutor 是 ExecutorService 的一个实现,使用线程池执行任务。它是最灵活和强大的线程池实现,允许我们自定义线程池的行为。
重要方法
- ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue): 构造一个新的 ThreadPoolExecutor。
- void execute(Runnable command): 执行提交的任务。
- Future<?> submit(Runnable task): 提交一个可运行的任务,并返回一个 Future 表示任务的结果。
- <T> Future<T> submit(Callable<T> task): 提交一个返回值的任务,并返回一个 Future 表示任务的结果。
- void shutdown(): 启动有序关闭,不再接受新任务,但会执行已提交的任务。
- List<Runnable> shutdownNow(): 尝试停止所有正在执行的任务,并返回等待执行的任务列表。
- boolean awaitTermination(long timeout, TimeUnit unit): 等待所有任务完成或超时。
6. ScheduledThreadPoolExecutor 类
功能
ScheduledThreadPoolExecutor 是 ScheduledExecutorService 的实现,使用线程池执行定时任务和周期性任务。
重要方法
- ScheduledThreadPoolExecutor(int corePoolSize): 构造一个新的 ScheduledThreadPoolExecutor。
- ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit): 在给定延迟后执行任务。
- <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit): 在给定延迟后执行任务,并返回 Future 表示任务的结果。
- ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit): 以固定速率定期执行任务。
- ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit): 以固定延迟定期执行任务。
7. ForkJoinPool 类
功能
ForkJoinPool 是 Java 7 引入的一种线程池实现,专为分治任务(fork/join)设计。它使用工作窃取算法来平衡线程间的负载,特别适用于递归任务。
重要方法
- ForkJoinPool(): 创建一个默认的 ForkJoinPool,其并行度等于 Runtime.getRuntime().availableProcessors()。
- ForkJoinPool(int parallelism): 创建一个具有指定并行度的 ForkJoinPool。
- void execute(ForkJoinTask<?> task): 执行一个 ForkJoinTask 任务。
- <T> T invoke(ForkJoinTask<T> task): 执行一个 ForkJoinTask 任务,并等待完成返回结果。
- void shutdown(): 启动有序关闭,不再接受新任务,但会执行已提交的任务。
- List<Runnable> shutdownNow(): 尝试停止所有正在执行的任务,并返回等待执行的任务列表。
- boolean awaitTermination(long timeout, TimeUnit unit): 等待所有任务完成或超时。