从线程池的核心原理、参数配置、常见用法、示例代码和注意事项等方面详细说明,帮你全面掌握 Android 线程池的应用。
线程池是一种重用线程的机制,核心作用包括:
避免频繁创建 / 销毁线程:减少系统开销(线程创建需要分配资源,销毁需要释放资源)。控制并发线程数:防止因线程过多导致的内存溢出或 CPU 占用过高。统一管理线程:提供任务排队、线程调度、异常处理等能力。提高响应速度:线程池中的线程可立即执行任务,无需等待创建。Android 的线程池基于
java.util.concurrent.ThreadPoolExecutor 实现,其构造函数的核心参数决定了线程池的行为:
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数(常驻线程,即使空闲也不会销毁)
int maximumPoolSize, // 最大线程数(线程池能容纳的总线程数)
long keepAliveTime, // 非核心线程的空闲存活时间
TimeUnit unit, // keepAliveTime 的时间单位(如 TimeUnit.SECONDS)
BlockingQueue<Runnable> workQueue, // 任务队列(存放等待执行的任务)
ThreadFactory threadFactory, // 线程工厂(创建线程的方式)
RejectedExecutionHandler handler // 拒绝策略(任务过多时的处理方式)
)
| 参数 | 作用 |
|---|---|
| corePoolSize | 核心线程数,线程池长期保持的线程数量,即使线程空闲也不会被回收(除非设置
allowCoreThreadTimeOut)。 |
| maximumPoolSize | 最大线程数,线程池允许创建的最大线程数。当任务队列满且核心线程都在工作时,会创建新线程直到达到该值。 |
| keepAliveTime | 非核心线程的空闲存活时间。如果非核心线程空闲超过该时间,会被回收。核心线程默认不会被回收(可通过
allowCoreThreadTimeOut(true)开启)。 |
| unit |
keepAliveTime的时间单位,如
TimeUnit.SECONDS(秒)、
TimeUnit.MILLISECONDS(毫秒)。 |
| workQueue | 任务队列,用于存放等待执行的任务。常见类型:
LinkedBlockingQueue(无界队列)、
ArrayBlockingQueue(有界队列)、
SynchronousQueue(同步队列)。 |
| threadFactory | 线程工厂,用于创建线程。可自定义线程名称、优先级、是否为守护线程等。 |
| handler | 拒绝策略,当任务队列满且最大线程数已达时,对新任务的处理方式。默认
AbortPolicy(抛出异常)。 |
| 队列类型 | 特点 |
|---|---|
| LinkedBlockingQueue | 无界队列(理论上可无限添加任务),不会触发拒绝策略,但可能导致内存溢出。 |
| ArrayBlockingQueue | 有界队列(指定容量),当队列满时会创建新线程(直到最大线程数)。 |
| SynchronousQueue | 同步队列,不存储任务,每个任务必须立即被线程执行(相当于 “直接提交”)。 |
| PriorityBlockingQueue | 优先级队列,任务按优先级执行(需实现
Comparable接口)。 |
| 拒绝策略 | 作用 |
|---|---|
| AbortPolicy(默认) | 抛出
RejectedExecutionException异常,终止任务。 |
| CallerRunsPolicy | 由提交任务的线程(如主线程)自己执行该任务。 |
| DiscardPolicy | 直接丢弃任务,不抛出异常。 |
| DiscardOldestPolicy | 丢弃任务队列中最旧的任务,然后尝试提交新任务。 |
Android 开发中,线程池的核心用途是处理后台任务(如网络请求、文件读写、数据解析等),避免阻塞主线程(UI 线程)。以下是常见用法:
// 1. 创建线程工厂(可选,用于自定义线程名称)
ThreadFactory threadFactory = new ThreadFactory() {
private int count = 0;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("MyThreadPool-" + count++); // 自定义线程名称
thread.setPriority(Thread.NORM_PRIORITY); // 设置优先级
return thread;
}
};
// 2. 创建任务队列(有界队列,容量为10)
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10);
// 3. 创建拒绝策略(可选,默认AbortPolicy)
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
// 4. 创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
10, // 非核心线程空闲存活时间(秒)
TimeUnit.SECONDS, // 时间单位
workQueue, // 任务队列
threadFactory, // 线程工厂
handler // 拒绝策略
);
// 5. 提交任务(Runnable或Callable)
// 方式1:提交Runnable任务(无返回值)
threadPool.execute(new Runnable() {
@Override
public void run() {
// 后台任务逻辑(如网络请求、文件读写)
Log.d("ThreadPool", "执行Runnable任务,线程名:" + Thread.currentThread().getName());
}
});
// 方式2:提交Callable任务(有返回值)
Future<String> future = threadPool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// 后台任务逻辑
Thread.sleep(1000);
return "任务执行完成";
}
});
// 6. 获取Callable任务的返回值(会阻塞当前线程,需在子线程中调用)
try {
String result = future.get(); // 等待任务完成并获取结果
Log.d("ThreadPool", "Callable任务结果:" + result);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
// 7. 关闭线程池(不再接受新任务,已提交任务继续执行)
// threadPool.shutdown();
// 8. 立即关闭线程池(尝试中断正在执行的任务,未执行的任务丢弃)
// threadPool.shutdownNow();
java.util.concurrent.Executors 提供了静态方法快速创建线程池,适合简单场景。但不推荐在 Android 中直接使用(尤其是
Executors.newFixedThreadPool、
Executors.newCachedThreadPool),因为可能导致内存溢出或线程数失控。
| 方法 | 特点 | 适用场景 |
|---|---|---|
| Executors.newFixedThreadPool(n) | 固定核心线程数(n),无界队列。线程数固定,不会创建非核心线程。 | 任务数量稳定,需要控制并发数。 |
| Executors.newCachedThreadPool() | 核心线程数 0,最大线程数 Integer.MAX_VALUE,空闲线程存活 60 秒。 | 任务数量少、执行时间短的场景。 |
| Executors.newSingleThreadExecutor() | 核心线程数 1,无界队列。所有任务串行执行。 | 需要串行执行任务的场景。 |
| Executors.newScheduledThreadPool(n) | 核心线程数 n,支持定时 / 周期性任务。 | 定时任务(如每隔 1 秒执行一次)。 |
// 创建定时线程池(核心线程数2)
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
// 1. 延迟1秒执行任务
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
Log.d("ThreadPool", "延迟1秒执行");
}
}, 1, TimeUnit.SECONDS);
// 2. 延迟2秒后,每隔3秒执行一次任务(周期性任务)
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Log.d("ThreadPool", "周期性任务执行");
}
}, 2, 3, TimeUnit.SECONDS);
// 3. 关闭定时线程池
// scheduledThreadPool.shutdown();
AsyncTask 是 Android 早期提供的轻量级异步任务工具,内部封装了线程池。但Android 11(API 30)已标记为过时,推荐使用
Coroutine或
ThreadPoolExecutor替代。
// 过时示例(不推荐使用)
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... voids) {
// 后台任务逻辑
return "任务结果";
}
@Override
protected void onPostExecute(String result) {
// 主线程更新UI
Log.d("AsyncTask", "结果:" + result);
}
}.execute();
Executors的静态方法(如
newFixedThreadPool、
newCachedThreadPool)存在以下问题:
newFixedThreadPool:使用无界队列(
LinkedBlockingQueue),任务过多时会导致内存溢出。
newCachedThreadPool:最大线程数为
Integer.MAX_VALUE,任务过多时会创建大量线程,导致 CPU 占用过高。
推荐:直接使用
ThreadPoolExecutor构造函数,手动配置核心参数(尤其是有界队列和合理的最大线程数)。
根据业务场景配置参数:
| 场景 | 核心线程数 | 最大线程数 | 任务队列 | 存活时间 |
|---|---|---|---|---|
| 网络请求(IO 密集型) | CPU 核心数 + 1 | CPU 核心数 * 2 | 有界队列(10-20) | 10-30 秒 |
| 数据解析(CPU 密集型) | CPU 核心数 | CPU 核心数 | 有界队列(5-10) | 0 秒(核心线程不回收) |
| 定时任务 | 1-2 | 1-2 | 无界队列 | 0 秒 |
获取 CPU 核心数:
java
运行
int CPU_COUNT = Runtime.getRuntime().availableProcessors(); // 通常为2、4、8等
execute()或
submit()提交任务。关闭:在应用退出或不再需要线程池时,调用
shutdown()或
shutdownNow()关闭线程池。
// 单例模式管理线程池
public class ThreadPoolManager {
private static ThreadPoolExecutor sThreadPool;
public static ThreadPoolExecutor getInstance() {
if (sThreadPool == null) {
synchronized (ThreadPoolManager.class) {
if (sThreadPool == null) {
int CPU_COUNT = Runtime.getRuntime().availableProcessors();
int corePoolSize = CPU_COUNT + 1;
int maximumPoolSize = CPU_COUNT * 2;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10);
sThreadPool = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
10,
TimeUnit.SECONDS,
workQueue,
new DefaultThreadFactory()
);
}
}
}
return sThreadPool;
}
// 关闭线程池
public static void shutdown() {
if (sThreadPool != null && !sThreadPool.isShutdown()) {
sThreadPool.shutdown();
}
}
// 自定义线程工厂
private static class DefaultThreadFactory implements ThreadFactory {
private int count = 0;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("AppThreadPool-" + count++);
thread.setDaemon(false); // 非守护线程(避免应用退出时线程被强制终止)
return thread;
}
}
}
Future.get()会阻塞当前线程,若在主线程中调用,会导致 UI 卡顿。应在子线程中获取结果,或使用
FutureTask的回调机制。
// 错误示例(主线程调用get())
Future<String> future = threadPool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "结果";
}
});
String result = future.get(); // 主线程阻塞1秒,导致UI卡顿
// 正确示例(子线程中获取结果)
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
String result = future.get(); // 子线程阻塞,不影响UI
Log.d("ThreadPool", "结果:" + result);
// 如需更新UI,通过Handler或runOnUiThread()
runOnUiThread(new Runnable() {
@Override
public void run() {
// 更新UI
}
});
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
});
run()方法中捕获异常。Callable 任务:异常会被封装到
ExecutionException中,需在
future.get()时捕获。
// Runnable任务的异常处理
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
// 后台任务逻辑
} catch (Exception e) {
Log.e("ThreadPool", "任务执行异常", e);
}
}
});
// Callable任务的异常处理
Future<String> future = threadPool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// 后台任务逻辑
return "结果";
}
});
try {
String result = future.get();
} catch (ExecutionException e) {
Log.e("ThreadPool", "任务执行异常", e.getCause()); // 获取原始异常
} catch (InterruptedException e) {
Log.e("ThreadPool", "任务被中断", e);
}
随着 Android 开发的发展,以下替代方案逐渐成为主流:
Coroutine是 Kotlin 提供的轻量级异步编程框架,底层基于线程池实现,语法更简洁,支持挂起函数(避免回调地狱)。
// 示例:使用Coroutine执行后台任务
GlobalScope.launch(Dispatchers.IO) { // IO线程池(适合网络/文件操作)
val result = fetchData() // 挂起函数(不阻塞线程)
withContext(Dispatchers.Main) { // 切换到主线程更新UI
textView.text = result
}
}
// 挂起函数(网络请求示例)
suspend fun fetchData(): String {
delay(1000) // 模拟网络请求延迟
return "网络数据"
}
RxJava是一个响应式编程框架,支持异步数据流处理,底层也使用线程池(
Schedulers)。
// 示例:使用RxJava执行后台任务
Observable.fromCallable(() -> {
// 后台任务逻辑
return "结果";
})
.subscribeOn(Schedulers.io()) // 后台线程池
.observeOn(AndroidSchedulers.mainThread()) // 主线程更新UI
.subscribe(result -> {
// 更新UI
}, error -> {
// 异常处理
});
future.get())。
ForegroundService,并在服务中管理线程池,避免应用退到后台后被系统杀死。Android 线程池的核心是
ThreadPoolExecutor,其参数配置直接影响性能和稳定性。实际开发中,应根据业务场景(IO 密集型 / CPU 密集型、任务数量、执行频率)合理配置核心参数,避免使用
Executors 的默认实现,同时注意线程池的生命周期管理和异常处理。
如果使用 Kotlin 开发,优先选择
Coroutine(更简洁、高效);如果需要复杂的异步数据流处理,可考虑
RxJava。