一、前言
在现代Java应用程序开发中,线程池已成为处理并发任务的标准模式。合理使用线程池能够显著提高系统性能,降低资源消耗,同时还能提供更好的线程管理能力。Java通过ThreadPoolExecutor
类提供了强大而灵活的线程池实现,本文将深入探讨其使用方法和内部实现原理。
(因为很少用CSDN写文章,目录的分点没搞明白,有些题目的数字号有问题,还请见谅)
二、线程池概述
2.1 为什么需要线程池
在传统模式下,每当需要执行异步任务时,我们通常会直接创建一个新线程:
new Thread(new Runnable() {
@Override
public void run() {
// 任务逻辑
}
}).start();
这种方式存在几个明显问题:
-
线程创建和销毁开销大:每次创建线程都需要操作系统资源,线程销毁后资源又需要回收
-
资源耗尽风险:无限制创建线程可能导致系统资源耗尽
-
缺乏管理:难以对线程进行统一管理和监控
线程池通过预先创建一定数量的线程并重复利用它们,有效解决了上述问题。
2.2 Java中的线程池体系
Java的线程池实现位于java.util.concurrent
包中,核心类继承关系如下:
Executor
├── ExecutorService
│ ├── AbstractExecutorService
│ │ └── ThreadPoolExecutor
│ └── ScheduledExecutorService
│ └── ScheduledThreadPoolExecutor
ThreadPoolExecutor
是最核心的实现类,提供了完整的线程池功能。Executors工具类提供了一些常用的线程池工厂方法,但了解ThreadPoolExecutor
的直接使用更为重要。
三、ThreadPoolExecutor核心参数
ThreadPoolExecutor
的完整构造函数如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
下面我们详细解析每个参数的含义和作用。
3.1 corePoolSize(核心线程数)
corePoolSize
指定了线程池中保持活动状态的最小线程数,即使它们处于空闲状态。除非设置了allowCoreThreadTimeOut
,否则核心线程不会被回收。
特点:
-
线程池刚创建时,线程数为0,随着任务到来逐渐增加到corePoolSize
-
当线程数达到corePoolSize后,新任务会被放入工作队列
-
核心线程通常不会被回收,保持常驻状态
设置建议:
-
对于CPU密集型任务,通常设置为CPU核心数+1
-
对于IO密集型任务,可以设置更大一些,具体取决于IO等待时间
3.2 maximumPoolSize(最大线程数)
maximumPoolSize
指定了线程池中允许存在的最大线程数。当工作队列已满且当前线程数小于maximumPoolSize时,线程池会创建新线程处理任务。
特点:
-
当线程数超过corePoolSize但小于maximumPoolSize时,新创建的线程会在空闲keepAliveTime时间后被回收
-
当线程数达到maximumPoolSize且队列已满时,会触发拒绝策略
设置建议:
-
需要根据系统资源和任务特性综合考虑
-
通常设置为corePoolSize的1.5-2倍
-
对于突发流量大的系统,可以设置更大一些
3.3 keepAliveTime(线程空闲时间)
keepAliveTime
指定了非核心线程空闲时的存活时间。当线程空闲时间超过keepAliveTime时,线程会被回收,直到线程数降至corePoolSize。
特点:
-
仅对超过corePoolSize的线程有效
-
如果设置了allowCoreThreadTimeOut(true),则核心线程也会受此参数控制
-
单位由TimeUnit参数指定
设置建议:
-
根据任务到达的频繁程度设置
-
对于突发任务较多的场景,可以设置较长一些
-
默认值通常为60秒
3.4 unit(时间单位)
unit
是keepAliveTime的时间单位,常用的有:
-
TimeUnit.NANOSECONDS
-
TimeUnit.MICROSECONDS
-
TimeUnit.MILLISECONDS
-
TimeUnit.SECONDS
-
TimeUnit.MINUTES
3.5 workQueue(工作队列)
workQueue
是用于保存等待执行的任务的阻塞队列。线程池的工作队列选择对线程池行为有重大影响。
常用队列类型:
-
ArrayBlockingQueue:基于数组的有界阻塞队列
-
特点:固定大小,公平性可选
-
适用场景:需要控制队列大小的场景
-
-
LinkedBlockingQueue:基于链表的阻塞队列
-
特点:默认无界(Integer.MAX_VALUE),也可设置为有界
-
适用场景:大多数场景,特别是任务到达速度波动大的情况
-
-
SynchronousQueue:不存储元素的阻塞队列
-
特点:每个插入操作必须等待一个移除操作
-
适用场景:需要直接传递任务的场景,通常配合较大的maximumPoolSize
-
-
PriorityBlockingQueue:具有优先级的无界阻塞队列
-
特点:按优先级排序,无界
-
适用场景:需要任务优先级的场景
-
队列选择策略:
-
对于短时突发任务:LinkedBlockingQueue或ArrayBlockingQueue
-
对于需要快速响应的任务:SynchronousQueue
-
对于需要优先级的任务:PriorityBlockingQueue
3.6 threadFactory(线程工厂)
threadFactory
用于创建新线程。通过自定义线程工厂,可以设置线程的名称、优先级、守护状态等。
默认实现:
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
自定义线程工厂示例:
public class CustomThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger threadNumber = new AtomicInteger(1);
public CustomThreadFactory(String poolName) {
namePrefix = poolName + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
t.setUncaughtExceptionHandler((thread, throwable) ->
System.err.println("Uncaught exception in " + thread.getName() + ": " + throwable));
return t;
}
}
3.7 handler(拒绝策略)
handler
是当线程池和工作队列都达到容量上限时,对新任务采取的处理策略。Java提供了四种内置策略:
-
AbortPolicy(默认):直接抛出RejectedExecutionException
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); }
-
CallerRunsPolicy:由调用线程直接执行该任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } }
-
DiscardPolicy:静默丢弃被拒绝的任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { }
-
DiscardOldestPolicy:丢弃队列中最旧的任务,然后尝试重新提交当前任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } }
自定义拒绝策略示例:
public class CustomRejectionPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 记录日志
System.err.println("Task rejected: " + r.toString());
// 保存到数据库或文件,稍后重试
saveTaskForLaterExecution(r);
// 发送告警
sendAlert();
}
private void saveTaskForLaterExecution(Runnable r) {
// 实现任务保存逻辑
}
private void sendAlert() {
// 实现告警逻辑
}
}
四、ThreadPoolExecutor执行流程
4.1 任务提交与执行流程
ThreadPoolExecutor
的任务执行流程是其核心逻辑,下面我们通过源码分析这一过程。
入口方法execute():
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 阶段1:当前线程数 < corePoolSize
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 阶段2:线程数 >= corePoolSize,尝试入队
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))
reject(command);
}
流程图:
开始
↓
提交任务command
↓
检查command是否为null → 是 → 抛出NullPointerException
↓ 否
获取当前线程池状态ctl
↓
if (当前线程数 < corePoolSize) → 是 → 尝试创建新Worker → 成功 → 结束
↓ 否 or 创建失败
if (线程池运行中 && 任务入队成功) → 是 → 双重检查线程池状态
↓
if (线程池不再运行 && 移除任务成功) → 是 → 执行拒绝策略
↓ 否
if (当前线程数 == 0) → 是 → 创建新Worker(不带初始任务)
↓ 否
结束
↓ 否 or 入队失败
if (尝试创建新Worker(非核心)) → 成功 → 结束
↓ 失败
执行拒绝策略
↓
结束
4.2 Worker内部类解析
Worker
是ThreadPoolExecutor
的内部类,负责封装工作线程和执行任务:
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread; // 实际执行任务的线程
Runnable firstTask; // 初始任务,可能为null
volatile long completedTasks; // 完成的任务数
Worker(Runnable firstTask) {
setState(-1); // 禁止中断直到runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
// 省略锁相关方法...
}
4.3 runWorker方法解析
runWorker
是实际执行任务的循环:
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 允许中断
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// 如果线程池正在停止,确保线程被中断
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
try {
task.run();
afterExecute(task, null);
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
4.4 getTask方法解析
getTask
方法负责从队列中获取任务:
private Runnable getTask() {
boolean timedOut = false; // 上次poll是否超时
for (;;) {
int c = ctl.get();
// 检查线程池状态
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 是否允许回收线程:允许核心线程超时或当前线程数超过核心数
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
五、线程池状态管理
ThreadPoolExecutor
使用一个AtomicInteger变量ctl
来同时维护线程池状态和线程数量:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 运行状态保存在高位
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;
// 获取运行状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取工作线程数
private static int workerCountOf(int c) { return c & CAPACITY; }
// 组合运行状态和工作线程数
private static int ctlOf(int rs, int wc) { return rs | wc; }
线程池有以下五种状态:
-
RUNNING:接受新任务并处理队列中的任务
-
SHUTDOWN:不接受新任务,但处理队列中的任务
-
STOP:不接受新任务,不处理队列中的任务,并中断正在进行的任务
-
TIDYING:所有任务已终止,workerCount为0,线程过渡到TIDYING状态将运行terminated()钩子方法
-
TERMINATED:terminated()方法已完成
状态转换图:
RUNNING -> SHUTDOWN
调用shutdown()
RUNNING/SHUTDOWN -> STOP
调用shutdownNow()
STOP -> TIDYING
当线程池和队列都为空时
SHUTDOWN -> TIDYING
当队列和线程池都为空时
TIDYING -> TERMINATED
当terminated()钩子方法完成时
六、线程池的异常处理
线程池的异常处理是一个容易被忽视但又非常重要的方面。ThreadPoolExecutor
提供了不同的任务提交方式,它们的异常处理机制也有所不同。
6.1 execute()方法的异常处理
execute()
方法提交的任务如果抛出未捕获异常,会导致执行该任务的线程终止:
executor.execute(() -> {
throw new RuntimeException("Oops!");
});
-
通过
ThreadFactory
设置UncaughtExceptionHandler
:
ThreadFactory factory = r -> {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler((thread, throwable) -> {
System.err.println("Exception in thread " + thread.getName() + ": " + throwable);
});
return t;
};
2.在任务内部捕获所有异常:
executor.execute(() -> {
try {
// 任务代码
} catch (Throwable t) {
// 处理异常
}
});
6.2 submit()方法的异常处理
submit()
方法返回一个Future
对象,异常会被封装在Future
中,只有在调用Future.get()
时才会抛出:
Future<?> future = executor.submit(() -> {
throw new RuntimeException("Oops!");
});
try {
future.get(); // 这里会抛出ExecutionException
} catch (ExecutionException e) {
Throwable cause = e.getCause(); // 获取实际异常
System.err.println("Task failed: " + cause);
}
submit()的三种形式:
Future<?> submit(Runnable task)
<T> Future<T> submit(Runnable task, T result)
<T> Future<T> submit(Callable<T> task)
6.3 afterExecute钩子方法
可以继承ThreadPoolExecutor
并重写afterExecute
方法来处理任务执行后的异常:
public class CustomThreadPool extends ThreadPoolExecutor {
// 构造方法省略...
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Future<?> future = (Future<?>) r;
if (future.isDone())
future.get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (t != null) {
System.err.println("Uncaught exception in thread pool: " + t);
// 其他处理逻辑...
}
}
}
6.4 异常处理最佳实践
-
明确任务边界:每个任务应该处理自己的异常,不传播到线程池
-
使用Callable代替Runnable:Callable可以更好地处理异常和返回值
-
合理使用Future:对于需要结果的任务,使用submit()和Future
-
记录未捕获异常:通过UncaughtExceptionHandler记录所有未捕获异常
-
监控线程池健康状态:定期检查线程池的异常情况
七、线程池的监控与调优
7.1 监控线程池状态
ThreadPoolExecutor
提供了一系列方法用于监控线程池状态:
// 获取核心线程数
int getCorePoolSize()
// 获取当前线程数
int getPoolSize()
// 获取活动线程数(正在执行任务的线程)
int getActiveCount()
// 获取最大允许线程数
int getMaximumPoolSize()
// 获取已完成任务数
long getCompletedTaskCount()
// 获取任务总数(已完成+正在执行+队列中等待)
long getTaskCount()
// 获取队列中的任务数
BlockingQueue<Runnable> getQueue()
自定义监控工具:
public class ThreadPoolMonitor implements Runnable {
private final ThreadPoolExecutor executor;
private final int intervalSec;
public ThreadPoolMonitor(ThreadPoolExecutor executor, int intervalSec) {
this.executor = executor;
this.intervalSec = intervalSec;
}
@Override
public void run() {
while (true) {
monitor();
try {
TimeUnit.SECONDS.sleep(intervalSec);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
private void monitor() {
System.out.println(
String.format("[monitor] [%d/%d] Active: %d, Completed: %d, Task: %d, Queue: %d/%d, isShutdown: %s, isTerminated: %s",
executor.getPoolSize(),
executor.getMaximumPoolSize(),
executor.getActiveCount(),
executor.getCompletedTaskCount(),
executor.getTaskCount(),
executor.getQueue().size(),
executor.getQueue().remainingCapacity(),
executor.isShutdown(),
executor.isTerminated()));
}
}
7.2 动态调整线程池参数
ThreadPoolExecutor
允许运行时调整核心参数:
// 设置核心线程数
void setCorePoolSize(int corePoolSize)
// 设置最大线程数
void setMaximumPoolSize(int maximumPoolSize)
// 设置线程空闲时间
void setKeepAliveTime(long time, TimeUnit unit)
// 允许/禁止核心线程超时
void allowCoreThreadTimeOut(boolean value)
动态调整示例:
public class DynamicThreadPoolAdjuster {
private final ThreadPoolExecutor executor;
public DynamicThreadPoolAdjuster(ThreadPoolExecutor executor) {
this.executor = executor;
}
public void adjustBasedOnLoad() {
int activeCount = executor.getActiveCount();
int poolSize = executor.getPoolSize();
int queueSize = executor.getQueue().size();
// 如果活动线程数等于池大小且队列不为空,考虑扩容
if (activeCount == poolSize && queueSize > 0) {
int newPoolSize = Math.min(
poolSize * 2,
executor.getMaximumPoolSize());
executor.setCorePoolSize(newPoolSize);
}
// 如果活动线程数远小于池大小,考虑缩容
else if (activeCount < poolSize / 2) {
int newPoolSize = Math.max(
poolSize / 2,
executor.getCorePoolSize());
executor.setCorePoolSize(newPoolSize);
}
}
}
7.3 线程池调优建议
-
CPU密集型任务:
-
corePoolSize = CPU核心数 + 1
-
maximumPoolSize = corePoolSize或稍大
-
使用有界队列防止资源耗尽
-
-
IO密集型任务:
-
corePoolSize可以设置较大(如CPU核心数*2)
-
maximumPoolSize可以设置更大(如CPU核心数*4)
-
考虑使用SynchronousQueue或较小的有界队列
-
-
混合型任务:
-
将任务分类,使用不同的线程池
-
或者根据IO等待时间比例调整线程数
-
-
通用建议:
-
避免无界队列,防止内存溢出
-
合理设置线程存活时间
-
为线程池命名,方便监控和排查问题
-
考虑使用自定义拒绝策略记录被拒绝的任务
-
八、线程池的常见陷阱与最佳实践
8.1 常见陷阱
-
无界队列导致OOM:
// 错误示例:使用无界队列且没有合理的拒绝策略 new ThreadPoolExecutor( 10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); // 默认无界
-
不合理的线程数设置:
-
核心线程数过大:资源浪费
-
最大线程数过小:无法应对突发流量
-
核心线程数过小:队列堆积
-
-
忽略任务异常:
executor.submit(() -> { throw new RuntimeException("This will be ignored!"); });
-
线程上下文切换开销:
-
线程数过多会导致大量CPU时间花在线程切换上
-
-
死锁风险:
-
线程池中的任务相互等待可能导致死锁
-
-
资源泄漏:
-
忘记关闭线程池会导致资源无法释放
-
8.2 最佳实践
-
合理配置线程池参数:
int corePoolSize = Runtime.getRuntime().availableProcessors() + 1; int maxPoolSize = corePoolSize * 2; ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maxPoolSize, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), new CustomThreadFactory("app-thread-pool"), new CustomRejectionPolicy());
-
使用有界队列:
new ArrayBlockingQueue<>(1000) // 根据系统负载设置合理大小
-
合理处理异常:
-
使用Future.get()检查异常
-
重写afterExecute方法
-
设置UncaughtExceptionHandler
-
-
正确关闭线程池:
executor.shutdown(); // 温和关闭 try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); // 强制关闭 } } catch (InterruptedException e) { executor.shutdownNow(); Thread.currentThread().interrupt(); }
-
避免在任务中使用ThreadLocal:
-
线程池中的线程会重用,可能导致ThreadLocal污染
-
-
为不同的任务类型使用不同的线程池:
-
将CPU密集型、IO密集型和关键任务分开处理
-
-
监控和动态调整:
-
定期监控线程池状态
-
根据负载动态调整参数
九、高级主题与扩展
9.1 ForkJoinPool与Work-Stealing算法
Java 7引入了
ForkJoinPool
,它使用工作窃取(work-stealing)算法,适合处理可以递归分解的任务。与
ThreadPoolExecutor
的主要区别: -
每个线程有自己的工作队列
-
当线程自己的队列为空时,可以从其他线程队列"窃取"任务
-
更适合处理大量小任务或可以递归分解的任务
-
参数配置:理解corePoolSize、maximumPoolSize、workQueue等参数的含义和相互关系
-
执行流程:掌握任务提交、线程创建、队列处理、拒绝策略的完整流程
-
异常处理:区分execute()和submit()的异常处理机制,合理捕获和处理异常
-
监控调优:建立线程池监控机制,根据实际负载动态调整参数
-
最佳实践:避免常见陷阱,遵循线程池使用的最佳实践
-
通过深入理解
ThreadPoolExecutor
的内部机制,开发者可以构建更健壮、高效的并发应用程序。9.2 CompletableFuture与异步编程
Java 8引入的
CompletableFuture
提供了更强大的异步编程能力,内部也使用线程池:CompletableFuture.supplyAsync(() -> { // 异步任务 return doSomething(); }, executor) // 可以指定自定义线程池 .thenApply(result -> { // 处理结果 return process(result); }) .exceptionally(ex -> { // 异常处理 return handleException(ex); });
9.3 定时任务执行
ScheduledThreadPoolExecutor
是ThreadPoolExecutor
的子类,支持定时和周期性任务:ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4); // 延迟执行 scheduler.schedule(() -> { System.out.println("Delayed task"); }, 1, TimeUnit.SECONDS); // 周期性执行 scheduler.scheduleAtFixedRate(() -> { System.out.println("Periodic task"); }, 0, 1, TimeUnit.SECONDS);
9.4 自定义线程池扩展
可以通过继承
ThreadPoolExecutor
并重写其钩子方法来实现自定义行为:public class PausableThreadPool extends ThreadPoolExecutor { private boolean isPaused; private final ReentrantLock pauseLock = new ReentrantLock(); private final Condition unpaused = pauseLock.newCondition(); public PausableThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override protected void beforeExecute(Thread t, Runnable r) { super.beforeExecute(t, r); pauseLock.lock(); try { while (isPaused) unpaused.await(); } catch (InterruptedException ie) { t.interrupt(); } finally { pauseLock.unlock(); } } public void pause() { pauseLock.lock(); try { isPaused = true; } finally { pauseLock.unlock(); } } public void resume() { pauseLock.lock(); try { isPaused = false; unpaused.signalAll(); } finally { pauseLock.unlock(); } } }
十、总结
ThreadPoolExecutor
是Java并发编程中的核心组件,合理使用线程池可以显著提高系统性能。本文详细剖析了其核心参数、执行流程、异常处理机制以及常见陷阱和最佳实践。关键点总结: -
参数配置:理解corePoolSize、maximumPoolSize、workQueue等参数的含义和相互关系
-
执行流程:掌握任务提交、线程创建、队列处理、拒绝策略的完整流程
-
通过深入理解
ThreadPoolExecutor
的内部机制,开发者可以构建更健壮、高效的并发应用程序。 -
异常处理:区分execute()和submit()的异常处理机制,合理捕获和处理异常
-
监控调优:建立线程池监控机制,根据实际负载动态调整参数
-
最佳实践:避免常见陷阱,遵循线程池使用的最佳实践
-