线程池是现代并发编程的基石 ,是Android中处理异步任务的工业级解决方案。线程池提供了更灵活、更高效的并发控制能力。
为什么需要线程池
java
// 问题代码:频繁创建销毁线程
public class NaiveThreadManager {
public void processTasks(List<Runnable> tasks) {
for (Runnable task : tasks) {
// 为每个任务创建新线程 ❌
new Thread(task).start();
// 如果有1000个任务,就会创建1000个线程!
// 这会导致:
// 1. 内存消耗大(每个线程需要1MB+栈内存)
// 2. CPU调度开销大(线程上下文切换)
// 3. 系统不稳定(可能超出系统线程限制)
}
}
}
线程创建的成本(以典型的Android设备为例):
| 成本类型 | 具体开销 |
|---|---|
| 内存开销 | 每个线程约1MB栈内存(可设置) |
| 创建时间 | 约1-5毫秒(包括系统调用、内存分配) |
| 销毁时间 | 约0.5-2毫秒 |
| 调度开销 | 线程切换需要保存/恢复寄存器、内存页表等 |
线程池的解决方案
java
// 使用线程池
public class ThreadPoolManager {
private ExecutorService executor;
public ThreadPoolManager() {
// 创建固定大小的线程池
executor = Executors.newFixedThreadPool(4); // 只有4个线程
}
public void processTasks(List<Runnable> tasks) {
for (Runnable task : tasks) {
executor.execute(task); // 重用已有的线程
}
}
}
线程池的核心价值:
- 线程复用:减少创建/销毁开销
- 资源控制:限制并发线程数量
- 任务管理:提供队列、拒绝策略等
- 监控统计:可获取任务完成情况
ThreadPoolExecutor的核心架构
七个核心参数
java
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
) { /* 实现 */ }
corePoolSize(核心线程数)
java
// 核心线程的特点:
// 1. 默认情况下,核心线程会一直存活(即使空闲)
// 2. 可以通过allowCoreThreadTimeOut(true)让核心线程超时终止
// 3. 线程池刚创建时,核心线程数为0(懒加载)
// Android中常见的核心线程数配置:
int availableProcessors = Runtime.getRuntime().availableProcessors();
int corePoolSize = Math.max(2, Math.min(availableProcessors - 1, 4));
// 通常取CPU核心数-1,范围在2-4之间
maximumPoolSize(最大线程数)
java
// 最大线程数限制:
// 1. 当任务队列满了,且当前线程数 < maximumPoolSize时,创建新线程
// 2. 创建的是"非核心线程"(救急线程)
// 3. 非核心线程空闲超过keepAliveTime会被回收
// 常见配置:
int maximumPoolSize = availableProcessors * 2 + 1;
// 公式:CPU核心数 × 2 + 1(考虑了超线程和I/O等待)
keepAliveTime(空闲线程存活时间)
java
// 只对非核心线程有效(除非设置了allowCoreThreadTimeOut)
long keepAliveTime = 30L; // 30秒
TimeUnit unit = TimeUnit.SECONDS;
// Android中的典型值:
// - CPU密集型任务:60-120秒
// - I/O密集型任务:10-30秒
// - 混合型任务:30-60秒
workQueue(任务队列)
java
// 常见的任务队列类型:
BlockingQueue<Runnable> queue;
// 1. SynchronousQueue(直接传递队列)
queue = new SynchronousQueue<>();
// 特点:不存储元素,每个插入操作必须等待一个移除操作
// 适用场景:线程数无限制,快速处理短任务
// 2. LinkedBlockingQueue(无界队列)
queue = new LinkedBlockingQueue<>();
// 特点:默认Integer.MAX_VALUE容量,可能导致内存溢出
// 适用场景:任务量不可控,但需要保证所有任务都被执行
// 3. ArrayBlockingQueue(有界队列)
queue = new ArrayBlockingQueue<>(100);
// 特点:固定容量,公平性可配置
// 适用场景:需要控制队列长度,防止资源耗尽
// 4. PriorityBlockingQueue(优先级队列)
queue = new PriorityBlockingQueue<>(11, Comparator.comparing(Task::getPriority));
// 特点:按优先级排序,可实现任务优先级调度
// 适用场景:需要区分任务优先级的场景
threadFactory(线程工厂)
java
ThreadFactory factory = new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix = "MyThreadPool-";
@Override
public Thread newThread(Runnable r) {
// 自定义线程属性
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
// 设置线程优先级
if (t.isDaemon()) {
t.setDaemon(false); // 默认为非守护线程
}
t.setPriority(Thread.NORM_PRIORITY); // 正常优先级
// 设置未捕获异常处理器
t.setUncaughtExceptionHandler((thread, throwable) -> {
Log.e("ThreadPool", "线程" + thread.getName() + "异常: " + throwable.getMessage());
});
return t;
}
};
handler(拒绝策略)
java
// 当线程池已关闭或队列已满时的处理策略
// 1. AbortPolicy(默认):抛出RejectedExecutionException
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
// 2. CallerRunsPolicy:由调用者线程执行任务
handler = new ThreadPoolExecutor.CallerRunsPolicy();
// 特点:不会丢弃任务,但可能阻塞调用者线程
// 3. DiscardPolicy:直接丢弃任务,不抛异常
handler = new ThreadPoolExecutor.DiscardPolicy();
// 4. DiscardOldestPolicy:丢弃队列中最旧的任务,然后重试
handler = new ThreadPoolExecutor.DiscardOldestPolicy();
// 5. 自定义策略
handler = (runnable, executor) -> {
// 记录日志
Log.w("ThreadPool", "任务被拒绝,保存到数据库等待重试");
// 将任务保存到数据库
saveTaskToDatabase(runnable);
// 或者尝试重新提交
try {
executor.getQueue().put(runnable); // 阻塞式插入
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
线程池状态机
java
// ThreadPoolExecutor的内部状态
private static final int RUNNING = -1 << COUNT_BITS; // 运行中
private static final int SHUTDOWN = 0 << COUNT_BITS; // 关闭中(不接受新任务)
private static final int STOP = 1 << COUNT_BITS; // 停止(中断所有线程)
private static final int TIDYING = 2 << COUNT_BITS; // 整理中(所有任务终止)
private static final int TERMINATED = 3 << COUNT_BITS; // 已终止
// 状态转换:
// RUNNING → SHUTDOWN: 调用shutdown()
// RUNNING/SHUTDOWN → STOP: 调用shutdownNow()
// STOP → TIDYING: 所有工作线程终止
// SHUTDOWN → TIDYING: 队列为空且所有工作线程终止
// TIDYING → TERMINATED: terminated()钩子执行完成
线程池的工作流程
任务执行流程图

execute()方法源码解析
java
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get(); // ctl包含线程池状态和线程数量
// 阶段1:当前线程数 < corePoolSize
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true)) // 创建核心线程
return;
c = ctl.get();
}
// 阶段2:线程数已达核心数,尝试加入队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 双重检查:如果线程池已关闭,则移除任务并拒绝
if (!isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false); // 保证至少有一个线程
}
// 阶段3:队列已满,尝试创建非核心线程
else if (!addWorker(command, false))
// 阶段4:线程数已达maximumPoolSize,执行拒绝策略
reject(command);
}
-
优先级:核心线程 > 任务队列 > 非核心线程 > 拒绝策略
-
懒加载:线程不是预先创建的,而是有任务时才创建
-
双重检查:加入队列后再次检查线程池状态
addWroker()方法解析
java
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 检查线程池状态
if (rs >= SHUTDOWN &&
!(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
// 检查线程数量限制
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 使用CAS增加线程计数
if (compareAndIncrementWorkerCount(c))
break retry; // 计数增加成功,跳出循环
c = ctl.get();
if (runStateOf(c) != rs)
continue retry;
}
}
// 创建Worker(内部类,封装了线程和任务)
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 再次检查状态
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // 线程已启动
throw new IllegalThreadStateException();
// 添加到workers集合
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
// 启动线程
if (t != null) {
t.start();
workerStarted = true;
}
}
} finally {
if (!workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
Worker类的内部机制
java
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
final Thread thread; // 实际执行的线程
Runnable firstTask; // 初始任务(可能为null)
volatile long completedTasks; // 完成的任务数
Worker(Runnable firstTask) {
setState(-1); // 初始状态,禁止中断
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
// 其他方法:锁状态管理、中断控制等
}
Worker的关键作用:
- 封装线程和任务
- 实现AQS锁:用于控制线程中断
- 统计完成任务数
Android中的线程池实践
AsyncTask的内部线程池配置
java
// AsyncTask的线程池配置
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, // 核心线程数:2-4
MAXIMUM_POOL_SIZE, // 最大线程数:CPU×2+1
KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(128), // 队列容量128
sThreadFactory
);
threadPoolExecutor.allowCoreThreadTimeOut(true); // 核心线程也会超时
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
设计分析:
- 核心线程数保守:2-4个,避免过多线程竞争CPU
- 队列容量有限:128,防止无限制积压
- 核心线程可超时:长时间空闲时释放资源
- 适合场景:短时、轻量的异步任务
不同任务类型的线程池配置
场景1:CPU密集型任务(如图像处理、计算)
java
public class CpuIntensiveThreadPool {
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// CPU密集型:线程数 ≈ CPU核心数
private static final int CORE_POOL_SIZE = CPU_COUNT;
private static final int MAX_POOL_SIZE = CPU_COUNT * 2; // 预留一些应对突发
// 使用有界队列,防止内存溢出
private static final BlockingQueue<Runnable> WORK_QUEUE =
new ArrayBlockingQueue<>(128);
// 线程存活时间较长,避免频繁创建
private static final long KEEP_ALIVE_TIME = 60L;
private final ThreadPoolExecutor executor;
public CpuIntensiveThreadPool() {
executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME, TimeUnit.SECONDS,
WORK_QUEUE,
new CustomThreadFactory("CPU-Intensive"),
new ThreadPoolExecutor.CallerRunsPolicy() // 饱和时让调用者执行
);
// 预热核心线程
executor.prestartAllCoreThreads();
}
}
场景2:I/O密集型任务(如网络请求、文件读写)
java
public class IoIntensiveThreadPool {
// I/O密集型:可以创建较多线程
// 因为线程大部分时间在等待I/O,不会占用CPU
private static final int CORE_POOL_SIZE = 4; // 基础线程数
private static final int MAX_POOL_SIZE = 20; // 最大线程数
// 使用同步队列,确保快速响应
private static final BlockingQueue<Runnable> WORK_QUEUE =
new SynchronousQueue<>();
// 线程存活时间较短,及时回收
private static final long KEEP_ALIVE_TIME = 10L;
private final ThreadPoolExecutor executor;
public IoIntensiveThreadPool() {
executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME, TimeUnit.SECONDS,
WORK_QUEUE,
new CustomThreadFactory("IO-Intensive"),
new ThreadPoolExecutor.AbortPolicy() // 饱和时快速失败
);
}
}
场景3:混合型任务
java
public class HybridThreadPool {
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 混合型:根据任务类型动态调整
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAX_POOL_SIZE = CPU_COUNT * 3;
// 使用优先级队列,区分任务优先级
private static final BlockingQueue<Runnable> WORK_QUEUE =
new PriorityBlockingQueue<>(256, Comparator.comparingInt(
task -> ((PrioritizedTask) task).getPriority()
));
private final ThreadPoolExecutor executor;
public HybridThreadPool() {
executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
30L, TimeUnit.SECONDS,
WORK_QUEUE,
new CustomThreadFactory("Hybrid"),
new CustomRejectionHandler() // 自定义拒绝策略
);
// 监控线程池状态
startMonitor();
}
// 优先级任务
static class PrioritizedTask implements Runnable {
private final int priority; // 数字越小优先级越高
private final Runnable task;
PrioritizedTask(int priority, Runnable task) {
this.priority = priority;
this.task = task;
}
int getPriority() { return priority; }
@Override
public void run() { task.run(); }
}
}
Executors工厂类的四种线程池
java
// 只需知道这四种类型及其特点
public class ExecutorsExample {
// 1. FixedThreadPool(固定大小线程池)
public void fixedThreadPoolExample() {
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
// 特点:
// - 核心线程数 = 最大线程数 = nThreads
// - 使用无界队列(LinkedBlockingQueue)
// - 适合负载较重的服务器,需要限制线程数量
// 风险:任务可能无限堆积,导致OOM
}
// 2. CachedThreadPool(缓存线程池)
public void cachedThreadPoolExample() {
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 特点:
// - 核心线程数 = 0,最大线程数 = Integer.MAX_VALUE
// - 使用同步队列(SynchronousQueue)
// - 线程空闲60秒后回收
// - 适合大量短时异步任务
// 风险:可能创建过多线程,导致OOM
}
// 3. SingleThreadExecutor(单线程线程池)
public void singleThreadExecutorExample() {
ExecutorService singlePool = Executors.newSingleThreadExecutor();
// 特点:
// - 只有一个线程,保证任务顺序执行
// - 使用无界队列
// - 适合需要保证顺序的任务
// 风险:HandlerThread的线程池版本,但更灵活
}
// 4. ScheduledThreadPool(定时线程池)
public void scheduledThreadPoolExample() {
ScheduledExecutorService scheduledPool =
Executors.newScheduledThreadPool(3);
// 特点:
// - 可以定时执行、延迟执行、周期性执行
// - 核心线程数可配置,最大线程数 = Integer.MAX_VALUE
// - 使用DelayedWorkQueue(延迟队列)
}
}
Executors创建的线程池在Android中不推荐使用,因为它们:
- 使用无界队列,可能造成OOM
- 默认配置不适合移动设备
- 缺乏监控和调优能力
线程池的高级特性
监控与统计
java
public class MonitorableThreadPool extends ThreadPoolExecutor {
public MonitorableThreadPool(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue, threadFactory, handler);
}
// 监控指标
private final AtomicLong totalTasks = new AtomicLong(0);
private final AtomicLong completedTasks = new AtomicLong(0);
private final AtomicLong failedTasks = new AtomicLong(0);
private final AtomicLong totalQueueTime = new AtomicLong(0);
@Override
public void execute(Runnable command) {
long submitTime = System.currentTimeMillis();
super.execute(() -> {
long queueTime = System.currentTimeMillis() - submitTime;
totalQueueTime.addAndGet(queueTime);
totalTasks.incrementAndGet();
try {
command.run();
completedTasks.incrementAndGet();
} catch (Exception e) {
failedTasks.incrementAndGet();
throw e;
}
});
}
// 获取监控数据
public ThreadPoolStats getStats() {
ThreadPoolStats stats = new ThreadPoolStats();
stats.setPoolSize(this.getPoolSize());
stats.setActiveCount(this.getActiveCount());
stats.setCorePoolSize(this.getCorePoolSize());
stats.setMaximumPoolSize(this.getMaximumPoolSize());
stats.setLargestPoolSize(this.getLargestPoolSize());
stats.setTaskCount(this.getTaskCount());
stats.setCompletedTaskCount(this.getCompletedTaskCount());
stats.setQueueSize(this.getQueue().size());
// 自定义指标
stats.setTotalTasks(totalTasks.get());
stats.setCompletedTasks(completedTasks.get());
stats.setFailedTasks(failedTasks.get());
if (totalTasks.get() > 0) {
stats.setAvgQueueTime(totalQueueTime.get() / totalTasks.get());
}
return stats;
}
public static class ThreadPoolStats {
private int poolSize; // 当前线程数
private int activeCount; // 活动线程数
private int corePoolSize; // 核心线程数
private int maximumPoolSize; // 最大线程数
private int largestPoolSize; // 历史最大线程数
private long taskCount; // 总任务数
private long completedTaskCount;// 已完成任务数
private int queueSize; // 队列大小
private long totalTasks; // 自定义:总任务数
private long completedTasks; // 自定义:已完成数
private long failedTasks; // 自定义:失败数
private long avgQueueTime; // 自定义:平均排队时间
// getters and setters
}
}
线程池的动态调整
java
public class DynamicThreadPool {
private ThreadPoolExecutor executor;
public DynamicThreadPool() {
executor = new ThreadPoolExecutor(
2, // 初始核心线程数
10, // 初始最大线程数
60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100)
);
}
// 动态调整核心线程数
public void setCorePoolSize(int newCoreSize) {
int oldCoreSize = executor.getCorePoolSize();
if (newCoreSize < oldCoreSize) {
// 减少核心线程数
executor.setCorePoolSize(newCoreSize);
} else if (newCoreSize > oldCoreSize) {
// 增加核心线程数
executor.setCorePoolSize(newCoreSize);
// 如果当前线程数 < 新核心数,创建新线程
if (executor.getPoolSize() < newCoreSize) {
int threadsToStart = newCoreSize - executor.getPoolSize();
for (int i = 0; i < threadsToStart; i++) {
executor.execute(() -> {
// 空任务,只是为了创建线程
});
}
}
}
}
// 动态调整最大线程数
public void setMaximumPoolSize(int newMaxSize) {
executor.setMaximumPoolSize(newMaxSize);
}
// 根据负载自动调整
public void autoAdjust() {
ThreadPoolExecutor executor = this.executor;
// 监控指标
int activeCount = executor.getActiveCount();
int poolSize = executor.getPoolSize();
int queueSize = executor.getQueue().size();
// 调整策略
if (queueSize > 50 && activeCount == poolSize) {
// 队列积压严重,且所有线程都在忙碌
int newCoreSize = Math.min(poolSize + 2, executor.getMaximumPoolSize());
setCorePoolSize(newCoreSize);
Log.d("DynamicThreadPool",
"增加核心线程数: " + poolSize + " -> " + newCoreSize +
" (队列大小: " + queueSize + ")");
}
else if (queueSize < 10 && poolSize > executor.getCorePoolSize()) {
// 队列空闲,且有超出核心的线程
// 这些线程会在keepAliveTime后自动回收
Log.d("DynamicThreadPool",
"队列空闲,非核心线程将在空闲时回收");
}
}
}
任务优先级与调度
java
public class PriorityThreadPool {
static class PriorityFutureTask extends FutureTask<Void>
implements Comparable<PriorityFutureTask> {
private final int priority;
public PriorityFutureTask(Runnable runnable, int priority) {
super(runnable, null);
this.priority = priority;
}
@Override
public int compareTo(PriorityFutureTask other) {
// 优先级数字越小,优先级越高
return Integer.compare(this.priority, other.priority);
}
}
private final ThreadPoolExecutor executor;
private final PriorityBlockingQueue<Runnable> queue;
public PriorityThreadPool(int corePoolSize, int maxPoolSize) {
queue = new PriorityBlockingQueue<>();
executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
60L, TimeUnit.SECONDS,
queue,
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
) {
@Override
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
if (runnable instanceof PrioritizedRunnable) {
PrioritizedRunnable pr = (PrioritizedRunnable) runnable;
return (RunnableFuture<T>) new PriorityFutureTask(runnable, pr.getPriority());
}
return super.newTaskFor(runnable, value);
}
};
}
public void submit(PrioritizedRunnable task) {
executor.execute(task);
}
public interface PrioritizedRunnable extends Runnable {
int getPriority(); // 0:最高, 1:高, 2:中, 3:低, 4:最低
}
// 使用示例
public void example() {
submit(() -> {
Log.d("Priority", "执行高优先级任务");
}, 1); // 高优先级
submit(() -> {
Log.d("Priority", "执行低优先级任务");
}, 4); // 低优先级
}
}
线程池的常见陷阱
内存泄漏:线程持有Context引用
java
// ❌ 错误示例:线程持有了Activity引用
public class LeakyThreadPool {
private final ExecutorService executor = Executors.newFixedThreadPool(2);
private Activity leakyActivity;
public void setActivity(Activity activity) {
this.leakyActivity = activity;
}
public void submitTask() {
executor.execute(() -> {
// 持有了Activity引用
SystemClock.sleep(30000); // 30秒
if (leakyActivity != null && !leakyActivity.isFinishing()) {
leakyActivity.runOnUiThread(() -> {
// 更新UI
});
}
});
}
}
// ✅ 正确示例:使用弱引用
public class SafeThreadPool {
private final ExecutorService executor = Executors.newFixedThreadPool(2);
private WeakReference<Activity> activityRef;
public void setActivity(Activity activity) {
this.activityRef = new WeakReference<>(activity);
}
public void submitTask() {
executor.execute(() -> {
SystemClock.sleep(30000);
Activity activity = activityRef != null ? activityRef.get() : null;
if (activity != null && !activity.isFinishing()) {
// 使用Application Context或者检查生命周期
activity.runOnUiThread(() -> {
// 更新UI
});
}
});
}
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
任务饥饿:错误配置导致某些任务永远得不到执行
java
public class StarvationExample {
public void demonstrateStarvation() {
// 错误配置:单线程 + 无界队列
ExecutorService executor = Executors.newSingleThreadExecutor();
// 提交一个长时间运行的任务
executor.submit(() -> {
SystemClock.sleep(10000); // 运行10秒
Log.d("Starvation", "长时间任务完成");
});
// 提交多个短任务
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
Log.d("Starvation", "短任务 " + taskId + " 开始");
SystemClock.sleep(100);
Log.d("Starvation", "短任务 " + taskId + " 完成");
});
}
// 问题:短任务需要等待10秒才能开始执行!
// 这就是"任务饥饿"现象
}
// 解决方案:使用合适的线程池配置
public void solution() {
// 方案1:使用多线程
ExecutorService executor = Executors.newFixedThreadPool(3);
// 方案2:使用优先级队列
ThreadPoolExecutor priorityExecutor = new ThreadPoolExecutor(
2, 4, 60, TimeUnit.SECONDS,
new PriorityBlockingQueue<>()
);
// 方案3:使用ScheduledExecutorService处理定时任务
ScheduledExecutorService scheduledExecutor =
Executors.newScheduledThreadPool(2);
}
}
线程泄露:忘记关闭线程池
java
public class ThreadLeakExample {
private ExecutorService executor;
public void start() {
executor = Executors.newFixedThreadPool(2);
// 提交任务...
executor.submit(() -> {
// 长时间运行的任务
});
}
// ❌ 忘记关闭线程池
// 即使Activity销毁,线程池中的线程依然存在
// 它们持有ThreadLeakExample的引用,导致内存泄漏
// ✅ 正确做法
public void cleanup() {
if (executor != null) {
// 优雅关闭
executor.shutdown();
try {
// 等待现有任务完成
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
// 强制关闭
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}
Android中的最佳实践
根据设备性能动态配置
java
public class AdaptiveThreadPool {
public static ExecutorService createOptimizedThreadPool() {
// 获取设备信息
int cpuCount = Runtime.getRuntime().availableProcessors();
long totalMemory = Runtime.getRuntime().totalMemory();
long maxMemory = Runtime.getRuntime().maxMemory();
// 低端设备配置
if (totalMemory < 2 * 1024 * 1024 * 1024L) { // 小于2GB
return createThreadPoolForLowEndDevice(cpuCount);
}
// 高端设备配置
else {
return createThreadPoolForHighEndDevice(cpuCount);
}
}
private static ExecutorService createThreadPoolForLowEndDevice(int cpuCount) {
// 保守配置
int corePoolSize = Math.max(1, cpuCount - 1);
int maxPoolSize = Math.min(cpuCount * 2, 8); // 最大8个线程
return new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
30L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(64), // 有界队列
new CustomThreadFactory("LowEnd"),
new ThreadPoolExecutor.DiscardOldestPolicy() // 丢弃旧任务
);
}
private static ExecutorService createThreadPoolForHighEndDevice(int cpuCount) {
// 激进配置
int corePoolSize = cpuCount;
int maxPoolSize = cpuCount * 4;
return new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(256),
new CustomThreadFactory("HighEnd"),
new ThreadPoolExecutor.CallerRunsPolicy() // 调用者执行
);
}
}
问题解析
Q1:ThreadPoolExecutor的各个参数有什么作用?
A:
- corePoolSize:核心线程数,即使空闲也会保留的线程数量
- maximumPoolSize:最大线程数,包括核心线程和非核心线程
- keepAliveTime:非核心线程的空闲存活时间
- unit:keepAliveTime的时间单位
- workQueue:任务队列,用于保存等待执行的任务
- threadFactory:创建新线程的工厂
- handler:拒绝策略,当线程池饱和时的处理方式
Q2:线程池的任务执行流程是怎样的?
A:
- 提交任务时,如果当前线程数 < corePoolSize,创建核心线程执行
- 如果线程数 ≥ corePoolSize,尝试将任务加入队列
- 如果队列已满,且线程数 < maximumPoolSize,创建非核心线程执行
- 如果队列已满,且线程数 ≥ maximumPoolSize,执行拒绝策略
简单记忆:核心线程 → 队列 → 非核心线程 → 拒绝
Q3:常用的阻塞队列有哪些?各有什么特点?
A:
- SynchronousQueue:不存储元素,每个插入必须等待一个移除
- LinkedBlockingQueue:基于链表的无界队列(默认Integer.MAX_VALUE)
- ArrayBlockingQueue:基于数组的有界队列
- PriorityBlockingQueue:支持优先级的无界队列
- DelayedWorkQueue:延迟队列,用于ScheduledThreadPool
Q4:线程池的拒绝策略有哪些?
A:
- AbortPolicy:默认策略,抛出RejectedExecutionException
- CallerRunsPolicy:用调用者线程执行任务
- DiscardPolicy:直接丢弃任务,不抛异常
- DiscardOldestPolicy:丢弃队列中最旧的任务,然后重试
- 自定义策略:实现RejectedExecutionHandler接口
Q5:如何合理配置线程池参数?
A:根据任务类型:
- CPU密集型:线程数 ≈ CPU核心数,避免过多线程上下文切换
- I/O密集型:线程数可以多一些,因为线程大部分时间在等待
- 混合型:根据具体情况调整,可监控线程利用率动态调整
经验公式:
-
CPU密集型:Ncpu + 1
-
I/O密集型:Ncpu × 2
-
最佳线程数 = Ncpu × Ucpu × (1 + W/C)
- Ncpu: CPU核心数
- Ucpu: 目标CPU利用率(0~1)
- W/C: 等待时间/计算时间
Q6:线程池有哪些状态?如何转换?
A:
- RUNNING:接收新任务,处理队列任务
- SHUTDOWN:不接收新任务,但处理队列任务
- STOP:不接收新任务,不处理队列任务,中断正在执行的任务
- TIDYING:所有任务已终止,workerCount为0
- TERMINATED:terminated()方法执行完成
转换:RUNNING → shutdown() → SHUTDOWN → 队列空且线程终止 → TIDYING → terminated() → TERMINATED
Q7:execute()和submit()有什么区别?
A:
-
execute() :提交Runnable任务,无返回值
-
submit() :可以提交Runnable或Callable任务,返回Future对象
- 可以获取任务执行结果
- 可以取消任务
- 可以判断任务是否完成
arduino
// execute示例
executor.execute(() -> {
System.out.println("执行任务");
});
// submit示例
Future<String> future = executor.submit(() -> {
return "任务结果";
});
String result = future.get(); // 获取结果
future.cancel(true); // 取消任务
总结
核心要点:
- 理解参数含义:7个参数决定线程池行为
- 掌握工作流程:核心线程 → 队列 → 非核心线程 → 拒绝
- 合理配置:根据任务类型(CPU/I/O密集型)配置参数
- 避免常见陷阱:内存泄漏、任务饥饿、线程泄露
- 善用监控:监控线程池状态,动态调整配置
与之前技术的对比:
| 技术 | 特点 | 适用场景 |
|---|---|---|
| HandlerThread | 单线程,顺序执行 | 简单后台任务,需要顺序执行 |
| AsyncTask | 固定模板,自动线程切换 | 简单异步任务(已弃用) |
| IntentService | Service + HandlerThread | 后台服务,自动停止(已弃用) |
| ThreadPoolExecutor | 灵活配置,强大控制 | 复杂并发场景,需要精细控制 |
现代发展趋势:
- 协程:更轻量,更简洁的并发方案
- WorkManager:替代IntentService的后台任务调度
- 响应式编程:RxJava的线程调度器