Android 线程池
线程池(ThreadPool)是一种多线程管理机制,用于复用线程、减少线程创建和销毁的开销,从而提高应用的性能和资源利用率。Android 提供了线程池的相关类和接口,开发者可以通过它们来高效地管理和使用线程。
线程池的优点
- 减少资源开销:
线程池通过复用已创建的线程,避免频繁创建和销毁线程的开销。 - 提高响应速度:
由于不需要频繁创建线程,任务可以更快地开始执行。 - 方便管理线程:
提供任务队列和线程的管理,能够更好地控制并发数量,避免资源耗尽。 - 线程复用:
提高系统效率,避免因线程过多导致的内存占用和调度开销。
Android 中的线程池核心类
Android 基于 Java 的线程池,主要使用的是 java.util.concurrent 包中的类和接口。
1. Executor 接口
- 顶层接口,用于执行任务,提供统一的线程管理入口。
- 常用实现类是
ThreadPoolExecutor。
2. ExecutorService 接口
- 扩展了
Executor,提供了管理线程池的方法,如shutdown()、submit()等。 - 常用实现类是
ThreadPoolExecutor。
3. ThreadPoolExecutor 类
- 核心线程池实现类,可以自定义线程池的行为。
- 通过其构造函数,可以设置核心线程数、最大线程数、线程存活时间等参数。
4. ScheduledThreadPoolExecutor 类
- 用于定时或周期性执行任务。
- 实现了
ScheduledExecutorService接口。
5. Executors 工具类
- 提供了一些静态方法,用于快速创建常见的线程池。
线程池的工作机制
线程池的工作机制可以总结为以下几个步骤:
- 提交任务: 任务通过
execute()或submit()提交给线程池。 - 任务队列: 任务首先被放入一个任务队列中。
- 核心线程: 如果线程池中的核心线程未达到
corePoolSize,则创建核心线程执行任务。 - 任务排队: 当核心线程已满时,任务会进入阻塞队列等待。
- 非核心线程: 如果任务队列已满且线程数小于
maximumPoolSize,则创建非核心线程处理任务。 - 拒绝策略: 如果线程池已满且任务队列也满,则根据拒绝策略处理任务。
ThreadPoolExecutor 构造方法
ThreadPoolExecutor 是线程池的核心实现类,构造方法如下:
java
复制代码
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 阻塞队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
参数说明
- corePoolSize:
核心线程数,核心线程会始终保持存活,除非allowCoreThreadTimeOut被设置为true。 - maximumPoolSize:
最大线程数,包括核心线程和非核心线程。 - keepAliveTime:
非核心线程的空闲存活时间,当超过该时间且没有任务时,线程会被销毁。 - workQueue:
阻塞队列,用于存储等待执行的任务。 - threadFactory:
线程工厂,用于创建新线程。 - handler:
拒绝策略,当线程池无法执行任务时的处理策略。
常见线程池类型(Executors 工具类)
1. FixedThreadPool(固定线程数线程池)
java
复制代码
ExecutorService executor = Executors.newFixedThreadPool(4);
-
特点:
- 核心线程数和最大线程数相等。
- 使用无界队列存储任务。
-
适用场景:
- 适用于负载稳定的场景,线程数固定避免资源耗尽。
2. CachedThreadPool(可缓存线程池)
java
复制代码
ExecutorService executor = Executors.newCachedThreadPool();
-
特点:
- 线程数不固定,最大为
Integer.MAX_VALUE。 - 没有核心线程,线程空闲时间超过 60 秒会被销毁。
- 线程数不固定,最大为
-
适用场景:
- 适用于大量短时间任务,线程复用效率高。
3. SingleThreadExecutor(单线程线程池)
java
复制代码
ExecutorService executor = Executors.newSingleThreadExecutor();
-
特点:
- 只有一个核心线程,确保任务按顺序执行。
-
适用场景:
- 适用于需要保证任务顺序执行的场景。
4. ScheduledThreadPool(定时任务线程池)
java
复制代码
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
-
特点:
- 支持定时或周期性任务。
-
适用场景:
- 适用于需要周期性执行任务的场景。
拒绝策略
线程池无法执行任务时,会根据指定的策略处理任务。常见策略有:
- AbortPolicy(默认) :
抛出RejectedExecutionException。 - CallerRunsPolicy:
使用提交任务的线程执行任务。 - DiscardPolicy:
丢弃任务,不抛出异常。 - DiscardOldestPolicy:
丢弃最早的任务,然后尝试执行新任务。
开发者也可以自定义拒绝策略,实现 RejectedExecutionHandler 接口。
示例:自定义线程池
java
复制代码
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60, // 非核心线程空闲存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(10), // 阻塞队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
// 提交任务
for (int i = 0; i < 15; i++) {
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务");
});
}
// 关闭线程池
executor.shutdown();
线程池的注意事项
-
避免使用
Executors创建线程池:Executors创建的线程池容易导致资源耗尽。- 推荐使用
ThreadPoolExecutor,更灵活、更可控。
-
线程池大小配置:
- 核心线程数可以根据设备 CPU 核心数设置。
- 非核心线程数和队列大小应结合任务特点进行调整。
-
避免阻塞任务:
- 线程池中的任务不宜执行耗时的阻塞操作,以免影响其他任务。
-
线程池的生命周期管理:
- 使用
shutdown()或shutdownNow()释放线程池资源。
- 使用
总结
线程池是 Android 开发中高效管理多线程任务的重要工具。它通过复用线程、合理控制并发数,减少了系统资源的浪费。开发者需要根据具体场景选择合适的线程池类型,并合理配置线程池参数以避免性能问题和资源耗尽。